Search in sources :

Example 1 with InvocationWriter

use of org.codehaus.groovy.classgen.asm.InvocationWriter in project groovy by apache.

the class StaticInvocationWriter method makeCall.

@Override
public void makeCall(final Expression origin, final Expression receiver, final Expression message, final Expression arguments, final MethodCallerMultiAdapter adapter, final boolean safe, final boolean spreadSafe, final boolean implicitThis) {
    if (origin.getNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION) != null) {
        StaticTypesWriterController staticController = (StaticTypesWriterController) controller;
        if (origin instanceof MethodCallExpression) {
            ((MethodCallExpression) origin).setMethodTarget(null);
        }
        InvocationWriter dynamicInvocationWriter = staticController.getRegularInvocationWriter();
        dynamicInvocationWriter.makeCall(origin, receiver, message, arguments, adapter, safe, spreadSafe, implicitThis);
        return;
    }
    if (implicitThis && tryImplicitReceiver(origin, message, arguments, adapter, safe, spreadSafe)) {
        return;
    }
    // if call is spread safe, replace it with a for in loop
    if (spreadSafe && origin instanceof MethodCallExpression) {
        // receiver expressions with side effects should not be visited twice, avoid by using a temporary variable
        Expression tmpReceiver = receiver;
        if (!(receiver instanceof VariableExpression) && !(receiver instanceof ConstantExpression)) {
            tmpReceiver = new TemporaryVariableExpression(receiver);
        }
        MethodVisitor mv = controller.getMethodVisitor();
        CompileStack compileStack = controller.getCompileStack();
        TypeChooser typeChooser = controller.getTypeChooser();
        OperandStack operandStack = controller.getOperandStack();
        ClassNode classNode = controller.getClassNode();
        int counter = labelCounter.incrementAndGet();
        // use a temporary variable for the arraylist in which the results of the spread call will be stored
        ConstructorCallExpression cce = ctorX(StaticCompilationVisitor.ARRAYLIST_CLASSNODE);
        cce.setNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, StaticCompilationVisitor.ARRAYLIST_CONSTRUCTOR);
        TemporaryVariableExpression result = new TemporaryVariableExpression(cce);
        result.visit(controller.getAcg());
        operandStack.pop();
        // if (receiver != null)
        tmpReceiver.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(tmpReceiver, classNode));
        Parameter iterator = new Parameter(componentType, "for$it$" + counter);
        VariableExpression iteratorAsVar = varX(iterator);
        MethodCallExpression origMCE = (MethodCallExpression) origin;
        MethodCallExpression newMCE = callX(iteratorAsVar, origMCE.getMethodAsString(), origMCE.getArguments());
        newMCE.setImplicitThis(false);
        newMCE.setMethodTarget(origMCE.getMethodTarget());
        newMCE.setSafe(true);
        MethodCallExpression add = callX(result, "add", newMCE);
        add.setImplicitThis(false);
        add.setMethodTarget(StaticCompilationVisitor.ARRAYLIST_ADD_METHOD);
        // for (e in receiver) { result.add(e?.method(arguments) }
        ForStatement stmt = new ForStatement(iterator, tmpReceiver, stmt(add));
        stmt.visit(controller.getAcg());
        // else { empty list }
        mv.visitLabel(ifnull);
        // end of if/else
        // return result list
        result.visit(controller.getAcg());
        // cleanup temporary variables
        if (tmpReceiver instanceof TemporaryVariableExpression) {
            ((TemporaryVariableExpression) tmpReceiver).remove(controller);
        }
        result.remove(controller);
    } else if (safe && origin instanceof MethodCallExpression) {
        // wrap call in an IFNULL check
        MethodVisitor mv = controller.getMethodVisitor();
        CompileStack compileStack = controller.getCompileStack();
        OperandStack operandStack = controller.getOperandStack();
        int counter = labelCounter.incrementAndGet();
        // if (receiver != null)
        ExpressionAsVariableSlot slot = new ExpressionAsVariableSlot(controller, receiver);
        slot.visit(controller.getAcg());
        operandStack.box();
        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);
        MethodCallExpression origMCE = (MethodCallExpression) origin;
        MethodCallExpression newMCE = callX(new VariableSlotLoader(slot.getType(), slot.getIndex(), controller.getOperandStack()), origMCE.getMethodAsString(), origMCE.getArguments());
        MethodNode methodTarget = origMCE.getMethodTarget();
        newMCE.setImplicitThis(origMCE.isImplicitThis());
        newMCE.setMethodTarget(methodTarget);
        newMCE.setSafe(false);
        newMCE.setSourcePosition(origMCE);
        newMCE.getObjectExpression().setSourcePosition(origMCE.getObjectExpression());
        newMCE.visit(controller.getAcg());
        compileStack.removeVar(slot.getIndex());
        ClassNode returnType = operandStack.getTopOperand();
        if (ClassHelper.isPrimitiveType(returnType) && !isPrimitiveVoid(returnType)) {
            operandStack.box();
        }
        Label endof = compileStack.createLocalLabel("endof_" + counter);
        mv.visitJumpInsn(GOTO, endof);
        mv.visitLabel(ifnull);
        // else { null }
        mv.visitInsn(ACONST_NULL);
        mv.visitLabel(endof);
    } else {
        if (origin instanceof AttributeExpression && (adapter == AsmClassGenerator.getField || adapter == AsmClassGenerator.getGroovyObjectField)) {
            CallSiteWriter callSiteWriter = controller.getCallSiteWriter();
            String fieldName = ((AttributeExpression) origin).getPropertyAsString();
            if (fieldName != null && callSiteWriter instanceof StaticTypesCallSiteWriter) {
                ClassNode receiverType = controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
                if (((StaticTypesCallSiteWriter) callSiteWriter).makeGetField(receiver, receiverType, fieldName, safe, false)) {
                    return;
                }
            }
        }
        super.makeCall(origin, receiver, message, arguments, adapter, safe, spreadSafe, implicitThis);
    }
}
Also used : OperandStack(org.codehaus.groovy.classgen.asm.OperandStack) DecompiledClassNode(org.codehaus.groovy.ast.decompiled.DecompiledClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) ExpressionAsVariableSlot(org.codehaus.groovy.classgen.asm.ExpressionAsVariableSlot) VariableSlotLoader(org.codehaus.groovy.classgen.asm.VariableSlotLoader) ConstructorCallExpression(org.codehaus.groovy.ast.expr.ConstructorCallExpression) ConstantExpression(org.codehaus.groovy.ast.expr.ConstantExpression) Label(org.objectweb.asm.Label) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) TemporaryVariableExpression(org.codehaus.groovy.transform.sc.TemporaryVariableExpression) AttributeExpression(org.codehaus.groovy.ast.expr.AttributeExpression) CompileStack(org.codehaus.groovy.classgen.asm.CompileStack) MethodVisitor(org.objectweb.asm.MethodVisitor) CallSiteWriter(org.codehaus.groovy.classgen.asm.CallSiteWriter) TypeChooser(org.codehaus.groovy.classgen.asm.TypeChooser) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) TemporaryVariableExpression(org.codehaus.groovy.transform.sc.TemporaryVariableExpression) ExtensionMethodNode(org.codehaus.groovy.transform.stc.ExtensionMethodNode) MethodNode(org.codehaus.groovy.ast.MethodNode) ConstantExpression(org.codehaus.groovy.ast.expr.ConstantExpression) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) ArrayExpression(org.codehaus.groovy.ast.expr.ArrayExpression) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) PropertyExpression(org.codehaus.groovy.ast.expr.PropertyExpression) ExpressionUtils.isSuperExpression(org.apache.groovy.ast.tools.ExpressionUtils.isSuperExpression) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) Expression(org.codehaus.groovy.ast.expr.Expression) ConstructorCallExpression(org.codehaus.groovy.ast.expr.ConstructorCallExpression) TemporaryVariableExpression(org.codehaus.groovy.transform.sc.TemporaryVariableExpression) ClassExpression(org.codehaus.groovy.ast.expr.ClassExpression) TupleExpression(org.codehaus.groovy.ast.expr.TupleExpression) AttributeExpression(org.codehaus.groovy.ast.expr.AttributeExpression) InvocationWriter(org.codehaus.groovy.classgen.asm.InvocationWriter) Parameter(org.codehaus.groovy.ast.Parameter) ForStatement(org.codehaus.groovy.ast.stmt.ForStatement)

Aggregations

ExpressionUtils.isSuperExpression (org.apache.groovy.ast.tools.ExpressionUtils.isSuperExpression)1 ClassNode (org.codehaus.groovy.ast.ClassNode)1 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)1 MethodNode (org.codehaus.groovy.ast.MethodNode)1 Parameter (org.codehaus.groovy.ast.Parameter)1 DecompiledClassNode (org.codehaus.groovy.ast.decompiled.DecompiledClassNode)1 ArgumentListExpression (org.codehaus.groovy.ast.expr.ArgumentListExpression)1 ArrayExpression (org.codehaus.groovy.ast.expr.ArrayExpression)1 AttributeExpression (org.codehaus.groovy.ast.expr.AttributeExpression)1 ClassExpression (org.codehaus.groovy.ast.expr.ClassExpression)1 ConstantExpression (org.codehaus.groovy.ast.expr.ConstantExpression)1 ConstructorCallExpression (org.codehaus.groovy.ast.expr.ConstructorCallExpression)1 Expression (org.codehaus.groovy.ast.expr.Expression)1 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)1 PropertyExpression (org.codehaus.groovy.ast.expr.PropertyExpression)1 TupleExpression (org.codehaus.groovy.ast.expr.TupleExpression)1 VariableExpression (org.codehaus.groovy.ast.expr.VariableExpression)1 ForStatement (org.codehaus.groovy.ast.stmt.ForStatement)1 CallSiteWriter (org.codehaus.groovy.classgen.asm.CallSiteWriter)1 CompileStack (org.codehaus.groovy.classgen.asm.CompileStack)1