Search in sources :

Example 36 with MethodVisitor

use of org.objectweb.asm.MethodVisitor in project groovy-core by groovy.

the class StaticTypesBinaryExpressionMultiTypeDispatcher method makeSetProperty.

private boolean makeSetProperty(final Expression receiver, final Expression message, final Expression arguments, final boolean safe, final boolean spreadSafe, final boolean implicitThis, final boolean isAttribute) {
    WriterController controller = getController();
    TypeChooser typeChooser = controller.getTypeChooser();
    ClassNode receiverType = typeChooser.resolveType(receiver, controller.getClassNode());
    String property = message.getText();
    boolean isThisExpression = receiver instanceof VariableExpression && ((VariableExpression) receiver).isThisExpression();
    if (isAttribute || (isThisExpression && receiverType.getDeclaredField(property) != null)) {
        ClassNode current = receiverType;
        FieldNode fn = null;
        while (fn == null && current != null) {
            fn = current.getDeclaredField(property);
            if (fn == null) {
                current = current.getSuperClass();
            }
        }
        if (fn != null && receiverType != current && !fn.isPublic()) {
            // check that direct access is allowed
            if (!fn.isProtected()) {
                return false;
            }
            String pkg1 = receiverType.getPackageName();
            String pkg2 = current.getPackageName();
            if (pkg1 != pkg2 && !pkg1.equals(pkg2)) {
                return false;
            }
            OperandStack operandStack = controller.getOperandStack();
            MethodVisitor mv = controller.getMethodVisitor();
            if (!fn.isStatic()) {
                receiver.visit(controller.getAcg());
            }
            arguments.visit(controller.getAcg());
            operandStack.doGroovyCast(fn.getOriginType());
            mv.visitFieldInsn(fn.isStatic() ? PUTSTATIC : PUTFIELD, BytecodeHelper.getClassInternalName(fn.getOwner()), property, BytecodeHelper.getTypeDescription(fn.getOriginType()));
            operandStack.remove(fn.isStatic() ? 1 : 2);
            return true;
        }
    }
    if (!isAttribute) {
        String setter = "set" + MetaClassHelper.capitalize(property);
        MethodNode setterMethod = receiverType.getSetterMethod(setter);
        ClassNode declaringClass = setterMethod != null ? setterMethod.getDeclaringClass() : null;
        if (isThisExpression && declaringClass != null && declaringClass.equals(controller.getClassNode())) {
            // this.x = ... shouldn't use a setter if in the same class
            setterMethod = null;
        } else if (setterMethod == null) {
            PropertyNode propertyNode = receiverType.getProperty(property);
            if (propertyNode != null) {
                int mods = propertyNode.getModifiers();
                if (!Modifier.isFinal(mods)) {
                    setterMethod = new MethodNode(setter, ACC_PUBLIC, ClassHelper.VOID_TYPE, new Parameter[] { new Parameter(propertyNode.getOriginType(), "value") }, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
                    setterMethod.setDeclaringClass(receiverType);
                }
            }
        }
        if (setterMethod != null) {
            Expression call = StaticPropertyAccessHelper.transformToSetterCall(receiver, setterMethod, arguments, implicitThis, safe, spreadSafe, // to be replaced with a proper test whether a return value should be used or not
            true, message);
            call.visit(controller.getAcg());
            return true;
        }
    }
    return false;
}
Also used : MethodVisitor(org.objectweb.asm.MethodVisitor)

Example 37 with MethodVisitor

use of org.objectweb.asm.MethodVisitor in project groovy-core by groovy.

the class StaticTypesBinaryExpressionMultiTypeDispatcher method transformSpreadOnLHS.

private void transformSpreadOnLHS(BinaryExpression origin) {
    PropertyExpression spreadExpression = (PropertyExpression) origin.getLeftExpression();
    Expression value = origin.getRightExpression();
    WriterController controller = getController();
    MethodVisitor mv = controller.getMethodVisitor();
    CompileStack compileStack = controller.getCompileStack();
    TypeChooser typeChooser = controller.getTypeChooser();
    OperandStack operandStack = controller.getOperandStack();
    ClassNode classNode = controller.getClassNode();
    int counter = labelCounter.incrementAndGet();
    Expression receiver = spreadExpression.getObjectExpression();
    // create an empty arraylist
    VariableExpression result = new VariableExpression(this.getClass().getSimpleName() + "$spreadresult" + counter, ARRAYLIST_CLASSNODE);
    ConstructorCallExpression cce = new ConstructorCallExpression(ARRAYLIST_CLASSNODE, ArgumentListExpression.EMPTY_ARGUMENTS);
    cce.setNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, ARRAYLIST_CONSTRUCTOR);
    DeclarationExpression declr = new DeclarationExpression(result, Token.newSymbol("=", spreadExpression.getLineNumber(), spreadExpression.getColumnNumber()), cce);
    declr.visit(controller.getAcg());
    // if (receiver != null)
    receiver.visit(controller.getAcg());
    Label ifnull = compileStack.createLocalLabel("ifnull_" + counter);
    mv.visitJumpInsn(IFNULL, ifnull);
    // receiver consumed by if()
    operandStack.remove(1);
    Label nonull = compileStack.createLocalLabel("nonull_" + counter);
    mv.visitLabel(nonull);
    ClassNode componentType = StaticTypeCheckingVisitor.inferLoopElementType(typeChooser.resolveType(receiver, classNode));
    Parameter iterator = new Parameter(componentType, "for$it$" + counter);
    VariableExpression iteratorAsVar = new VariableExpression(iterator);
    PropertyExpression pexp = spreadExpression instanceof AttributeExpression ? new AttributeExpression(iteratorAsVar, spreadExpression.getProperty(), true) : new PropertyExpression(iteratorAsVar, spreadExpression.getProperty(), true);
    pexp.setImplicitThis(spreadExpression.isImplicitThis());
    pexp.setSourcePosition(spreadExpression);
    BinaryExpression assignment = new BinaryExpression(pexp, origin.getOperation(), value);
    MethodCallExpression add = new MethodCallExpression(result, "add", assignment);
    add.setMethodTarget(ARRAYLIST_ADD_METHOD);
    // for (e in receiver) { result.add(e?.method(arguments) }
    ForStatement stmt = new ForStatement(iterator, receiver, new ExpressionStatement(add));
    stmt.visit(controller.getAcg());
    // else { empty list }
    mv.visitLabel(ifnull);
    // end of if/else
    // return result list
    result.visit(controller.getAcg());
}
Also used : Label(org.objectweb.asm.Label) MethodVisitor(org.objectweb.asm.MethodVisitor) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) ForStatement(org.codehaus.groovy.ast.stmt.ForStatement)

Example 38 with MethodVisitor

use of org.objectweb.asm.MethodVisitor in project groovy-core by groovy.

the class StaticTypesBinaryExpressionMultiTypeDispatcher method writePostOrPrefixMethod.

@Override
protected void writePostOrPrefixMethod(int op, String method, Expression expression, Expression orig) {
    MethodNode mn = orig.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
    WriterController controller = getController();
    OperandStack operandStack = controller.getOperandStack();
    if (mn != null) {
        operandStack.pop();
        MethodCallExpression call = new MethodCallExpression(expression, method, ArgumentListExpression.EMPTY_ARGUMENTS);
        call.setMethodTarget(mn);
        call.visit(controller.getAcg());
        return;
    }
    ClassNode top = operandStack.getTopOperand();
    if (ClassHelper.isPrimitiveType(top) && (ClassHelper.isNumberType(top) || char_TYPE.equals(top))) {
        MethodVisitor mv = controller.getMethodVisitor();
        if (WideningCategories.isIntCategory(top) || char_TYPE.equals(top)) {
            mv.visitInsn(ICONST_1);
        } else if (long_TYPE.equals(top)) {
            mv.visitInsn(LCONST_1);
        } else if (float_TYPE.equals(top)) {
            mv.visitInsn(FCONST_1);
        } else if (double_TYPE.equals(top)) {
            mv.visitInsn(DCONST_1);
        }
        if ("next".equals(method)) {
            if (WideningCategories.isIntCategory(top) || char_TYPE.equals(top)) {
                mv.visitInsn(IADD);
            } else if (long_TYPE.equals(top)) {
                mv.visitInsn(LADD);
            } else if (float_TYPE.equals(top)) {
                mv.visitInsn(FADD);
            } else if (double_TYPE.equals(top)) {
                mv.visitInsn(DADD);
            }
        } else {
            if (WideningCategories.isIntCategory(top) || char_TYPE.equals(top)) {
                mv.visitInsn(ISUB);
            } else if (long_TYPE.equals(top)) {
                mv.visitInsn(LSUB);
            } else if (float_TYPE.equals(top)) {
                mv.visitInsn(FSUB);
            } else if (double_TYPE.equals(top)) {
                mv.visitInsn(DSUB);
            }
        }
        return;
    }
    super.writePostOrPrefixMethod(op, method, expression, orig);
}
Also used : MethodVisitor(org.objectweb.asm.MethodVisitor)

Example 39 with MethodVisitor

use of org.objectweb.asm.MethodVisitor in project groovy-core by groovy.

the class StatementWriter method writeTryCatchFinally.

public void writeTryCatchFinally(TryCatchStatement statement) {
    controller.getAcg().onLineNumber(statement, "visitTryCatchFinally");
    writeStatementLabel(statement);
    MethodVisitor mv = controller.getMethodVisitor();
    CompileStack compileStack = controller.getCompileStack();
    OperandStack operandStack = controller.getOperandStack();
    Statement tryStatement = statement.getTryStatement();
    final Statement finallyStatement = statement.getFinallyStatement();
    // start try block, label needed for exception table
    Label tryStart = new Label();
    mv.visitLabel(tryStart);
    BlockRecorder tryBlock = makeBlockRecorder(finallyStatement);
    tryBlock.startRange(tryStart);
    tryStatement.visit(controller.getAcg());
    // goto finally part
    Label finallyStart = new Label();
    mv.visitJumpInsn(GOTO, finallyStart);
    Label tryEnd = new Label();
    mv.visitLabel(tryEnd);
    tryBlock.closeRange(tryEnd);
    // pop for "makeBlockRecorder(finallyStatement)"
    controller.getCompileStack().pop();
    BlockRecorder catches = makeBlockRecorder(finallyStatement);
    for (CatchStatement catchStatement : statement.getCatchStatements()) {
        ClassNode exceptionType = catchStatement.getExceptionType();
        String exceptionTypeInternalName = BytecodeHelper.getClassInternalName(exceptionType);
        // start catch block, label needed for exception table
        Label catchStart = new Label();
        mv.visitLabel(catchStart);
        catches.startRange(catchStart);
        // create exception variable and store the exception
        Parameter exceptionVariable = catchStatement.getVariable();
        compileStack.pushState();
        compileStack.defineVariable(exceptionVariable, true);
        // handle catch body
        catchStatement.visit(controller.getAcg());
        // place holder to avoid problems with empty catch blocks
        mv.visitInsn(NOP);
        // pop for the variable
        controller.getCompileStack().pop();
        // end of catch
        Label catchEnd = new Label();
        mv.visitLabel(catchEnd);
        catches.closeRange(catchEnd);
        // goto finally start
        mv.visitJumpInsn(GOTO, finallyStart);
        compileStack.writeExceptionTable(tryBlock, catchStart, exceptionTypeInternalName);
    }
    // Label used to handle exceptions in catches and regularly
    // visited finals.
    Label catchAny = new Label();
    // add "catch any" block to exception table for try part we do this 
    // after the exception blocks, because else this one would supersede
    // any of those otherwise
    compileStack.writeExceptionTable(tryBlock, catchAny, null);
    // same for the catch parts
    compileStack.writeExceptionTable(catches, catchAny, null);
    // pop for "makeBlockRecorder(catches)"
    compileStack.pop();
    // start finally
    mv.visitLabel(finallyStart);
    finallyStatement.visit(controller.getAcg());
    //**
    mv.visitInsn(NOP);
    // goto after all-catching block
    Label skipCatchAll = new Label();
    mv.visitJumpInsn(GOTO, skipCatchAll);
    // start a block catching any Exception
    mv.visitLabel(catchAny);
    //store exception
    //TODO: maybe define a Throwable and use it here instead of Object
    operandStack.push(ClassHelper.OBJECT_TYPE);
    int anyExceptionIndex = compileStack.defineTemporaryVariable("exception", true);
    finallyStatement.visit(controller.getAcg());
    // load the exception and rethrow it
    mv.visitVarInsn(ALOAD, anyExceptionIndex);
    mv.visitInsn(ATHROW);
    mv.visitLabel(skipCatchAll);
}
Also used : BlockRecorder(org.codehaus.groovy.classgen.asm.CompileStack.BlockRecorder) ClassNode(org.codehaus.groovy.ast.ClassNode) CatchStatement(org.codehaus.groovy.ast.stmt.CatchStatement) TryCatchStatement(org.codehaus.groovy.ast.stmt.TryCatchStatement) Statement(org.codehaus.groovy.ast.stmt.Statement) WhileStatement(org.codehaus.groovy.ast.stmt.WhileStatement) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) ThrowStatement(org.codehaus.groovy.ast.stmt.ThrowStatement) CaseStatement(org.codehaus.groovy.ast.stmt.CaseStatement) DoWhileStatement(org.codehaus.groovy.ast.stmt.DoWhileStatement) ContinueStatement(org.codehaus.groovy.ast.stmt.ContinueStatement) ForStatement(org.codehaus.groovy.ast.stmt.ForStatement) BreakStatement(org.codehaus.groovy.ast.stmt.BreakStatement) ReturnStatement(org.codehaus.groovy.ast.stmt.ReturnStatement) CatchStatement(org.codehaus.groovy.ast.stmt.CatchStatement) SynchronizedStatement(org.codehaus.groovy.ast.stmt.SynchronizedStatement) EmptyStatement(org.codehaus.groovy.ast.stmt.EmptyStatement) SwitchStatement(org.codehaus.groovy.ast.stmt.SwitchStatement) IfStatement(org.codehaus.groovy.ast.stmt.IfStatement) AssertStatement(org.codehaus.groovy.ast.stmt.AssertStatement) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) TryCatchStatement(org.codehaus.groovy.ast.stmt.TryCatchStatement) Label(org.objectweb.asm.Label) Parameter(org.codehaus.groovy.ast.Parameter) MethodVisitor(org.objectweb.asm.MethodVisitor)

Example 40 with MethodVisitor

use of org.objectweb.asm.MethodVisitor in project groovy-core by groovy.

the class StatementWriter method writeForLoopWithClosureList.

protected void writeForLoopWithClosureList(ForStatement loop) {
    controller.getAcg().onLineNumber(loop, "visitForLoop");
    writeStatementLabel(loop);
    MethodVisitor mv = controller.getMethodVisitor();
    controller.getCompileStack().pushLoop(loop.getVariableScope(), loop.getStatementLabels());
    ClosureListExpression clExpr = (ClosureListExpression) loop.getCollectionExpression();
    controller.getCompileStack().pushVariableScope(clExpr.getVariableScope());
    List expressions = clExpr.getExpressions();
    int size = expressions.size();
    // middle element is condition, lower half is init, higher half is increment
    int condIndex = (size - 1) / 2;
    // visit init
    for (int i = 0; i < condIndex; i++) {
        visitExpressionOrStatement(expressions.get(i));
    }
    Label continueLabel = controller.getCompileStack().getContinueLabel();
    Label breakLabel = controller.getCompileStack().getBreakLabel();
    Label cond = new Label();
    mv.visitLabel(cond);
    // visit condition leave boolean on stack
    {
        Expression condExpr = (Expression) expressions.get(condIndex);
        int mark = controller.getOperandStack().getStackLength();
        condExpr.visit(controller.getAcg());
        controller.getOperandStack().castToBool(mark, true);
    }
    // jump if we don't want to continue
    // note: ifeq tests for ==0, a boolean is 0 if it is false
    controller.getOperandStack().jump(IFEQ, breakLabel);
    // Generate the loop body
    loop.getLoopBlock().visit(controller.getAcg());
    // visit increment
    mv.visitLabel(continueLabel);
    for (int i = condIndex + 1; i < size; i++) {
        visitExpressionOrStatement(expressions.get(i));
    }
    // jump to test the condition again
    mv.visitJumpInsn(GOTO, cond);
    // loop end
    mv.visitLabel(breakLabel);
    controller.getCompileStack().pop();
    controller.getCompileStack().pop();
}
Also used : ClosureListExpression(org.codehaus.groovy.ast.expr.ClosureListExpression) ConstantExpression(org.codehaus.groovy.ast.expr.ConstantExpression) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) EmptyExpression(org.codehaus.groovy.ast.expr.EmptyExpression) Expression(org.codehaus.groovy.ast.expr.Expression) ClosureListExpression(org.codehaus.groovy.ast.expr.ClosureListExpression) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) Label(org.objectweb.asm.Label) List(java.util.List) MethodVisitor(org.objectweb.asm.MethodVisitor)

Aggregations

MethodVisitor (org.objectweb.asm.MethodVisitor)407 Label (org.objectweb.asm.Label)114 ClassNode (org.codehaus.groovy.ast.ClassNode)57 ClassWriter (org.objectweb.asm.ClassWriter)34 Type (org.objectweb.asm.Type)34 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)30 ArrayList (java.util.ArrayList)27 Test (org.junit.Test)23 ClassVisitor (org.objectweb.asm.ClassVisitor)23 Parameter (org.codehaus.groovy.ast.Parameter)22 LinkedList (java.util.LinkedList)19 InterfaceHelperClassNode (org.codehaus.groovy.ast.InterfaceHelperClassNode)18 AsmClassGenerator (org.codehaus.groovy.classgen.AsmClassGenerator)18 BytecodeExpression (org.codehaus.groovy.classgen.BytecodeExpression)18 FieldVisitor (org.objectweb.asm.FieldVisitor)18 ArgumentListExpression (org.codehaus.groovy.ast.expr.ArgumentListExpression)17 ClassReader (org.objectweb.asm.ClassReader)17 List (java.util.List)16 ExpressionStatement (org.codehaus.groovy.ast.stmt.ExpressionStatement)16 MethodDescription (net.bytebuddy.description.method.MethodDescription)15