Search in sources :

Example 1 with VariableSlotLoader

use of org.codehaus.groovy.classgen.asm.VariableSlotLoader 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)

Example 2 with VariableSlotLoader

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

the class StaticTypesBinaryExpressionMultiTypeDispatcher method assignToArray.

@Override
protected void assignToArray(final Expression enclosing, final Expression receiver, final Expression subscript, final Expression rhsValueLoader, final boolean safe) {
    ClassNode receiverType = controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
    if (receiverType.isArray() && !safe && binExpWriter[getOperandType(receiverType.getComponentType())].arraySet(true)) {
        super.assignToArray(enclosing, receiver, subscript, rhsValueLoader, safe);
    } else {
        // GROOVY-6061
        if (rhsValueLoader instanceof VariableSlotLoader && enclosing instanceof BinaryExpression) {
            rhsValueLoader.putNodeMetaData(INFERRED_TYPE, controller.getTypeChooser().resolveType(enclosing, controller.getClassNode()));
        }
        // GROOVY-9771
        receiver.visit(new StaticCompilationVisitor(controller.getSourceUnit(), controller.getClassNode()));
        // replace assignment to a subscript operator with a method call
        // e.g. x[5] = 10 -> methodCall(x, "putAt", [5, 10])
        MethodCallExpression call = callX(receiver, "putAt", args(subscript, rhsValueLoader));
        call.setSafe(safe);
        call.setSourcePosition(enclosing);
        OperandStack operandStack = controller.getOperandStack();
        int height = operandStack.getStackLength();
        call.visit(controller.getAcg());
        operandStack.pop();
        operandStack.remove(operandStack.getStackLength() - height);
        // return value of assignment
        rhsValueLoader.visit(controller.getAcg());
    }
}
Also used : OperandStack(org.codehaus.groovy.classgen.asm.OperandStack) ClassNode(org.codehaus.groovy.ast.ClassNode) VariableSlotLoader(org.codehaus.groovy.classgen.asm.VariableSlotLoader) BinaryExpression(org.codehaus.groovy.ast.expr.BinaryExpression) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) StaticCompilationVisitor(org.codehaus.groovy.transform.sc.StaticCompilationVisitor)

Example 3 with VariableSlotLoader

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

the class StaticTypesCallSiteWriter method fallbackAttributeOrPropertySite.

@Override
public void fallbackAttributeOrPropertySite(final PropertyExpression expression, final Expression objectExpression, final String name, final MethodCallerMultiAdapter adapter) {
    CompileStack compileStack = controller.getCompileStack();
    OperandStack operandStack = controller.getOperandStack();
    if (name != null && compileStack.isLHS()) {
        boolean[] isClassReceiver = new boolean[1];
        ClassNode receiverType = getPropertyOwnerType(objectExpression, isClassReceiver);
        if (adapter == AsmClassGenerator.setField || adapter == AsmClassGenerator.setGroovyObjectField) {
            if (setField(expression, objectExpression, receiverType, name))
                return;
        }
        if (isThisExpression(objectExpression)) {
            ClassNode classNode = controller.getClassNode();
            FieldNode fieldNode = receiverType.getField(name);
            if (fieldNode != null && fieldNode.isPrivate() && !receiverType.equals(classNode) && StaticInvocationWriter.isPrivateBridgeMethodsCallAllowed(receiverType, classNode)) {
                Map<String, MethodNode> mutators = receiverType.redirect().getNodeMetaData(StaticCompilationMetadataKeys.PRIVATE_FIELDS_MUTATORS);
                if (mutators != null) {
                    MethodNode methodNode = mutators.get(name);
                    if (methodNode != null) {
                        ClassNode rhsType = operandStack.getTopOperand();
                        int i = compileStack.defineTemporaryVariable("$rhs", rhsType, true);
                        VariableSlotLoader rhsValue = new VariableSlotLoader(rhsType, i, operandStack);
                        MethodCallExpression call = callX(objectExpression, methodNode.getName(), args(fieldNode.isStatic() ? nullX() : objectExpression, rhsValue));
                        call.setImplicitThis(expression.isImplicitThis());
                        call.setSpreadSafe(expression.isSpreadSafe());
                        call.setSafe(expression.isSafe());
                        call.setMethodTarget(methodNode);
                        call.visit(controller.getAcg());
                        // GROOVY-9892: assuming that the mutator method has a return value, make sure the operand
                        // stack is not polluted with the result of the method call
                        operandStack.pop();
                        compileStack.removeVar(i);
                        return;
                    }
                }
            }
        }
        if (isOrImplements(receiverType, MAP_TYPE) && !isClassReceiver[0]) {
            MethodVisitor mv = controller.getMethodVisitor();
            // store value in temporary variable
            ClassNode rhsType = operandStack.getTopOperand();
            int rhs = compileStack.defineTemporaryVariable("$rhs", rhsType, true);
            // push receiver on stack
            compileStack.pushLHS(false);
            objectExpression.visit(controller.getAcg());
            compileStack.popLHS();
            // check if receiver null
            Label skip = new Label();
            if (expression.isSafe()) {
                mv.visitInsn(DUP);
                mv.visitJumpInsn(IFNULL, skip);
            }
            mv.visitLdcInsn(name);
            BytecodeHelper.load(mv, rhsType, rhs);
            if (isPrimitiveType(rhsType))
                BytecodeHelper.doCastToWrappedType(mv, rhsType, getWrapper(rhsType));
            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", true);
            if (expression.isSafe()) {
                mv.visitLabel(skip);
            }
            // no return value
            operandStack.pop();
            compileStack.removeVar(rhs);
            return;
        }
    }
    super.fallbackAttributeOrPropertySite(expression, objectExpression, name, adapter);
}
Also used : OperandStack(org.codehaus.groovy.classgen.asm.OperandStack) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) VariableSlotLoader(org.codehaus.groovy.classgen.asm.VariableSlotLoader) FieldNode(org.codehaus.groovy.ast.FieldNode) Label(org.objectweb.asm.Label) CompileStack(org.codehaus.groovy.classgen.asm.CompileStack) MethodVisitor(org.objectweb.asm.MethodVisitor) MethodNode(org.codehaus.groovy.ast.MethodNode) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression)

Aggregations

ClassNode (org.codehaus.groovy.ast.ClassNode)3 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)3 OperandStack (org.codehaus.groovy.classgen.asm.OperandStack)3 VariableSlotLoader (org.codehaus.groovy.classgen.asm.VariableSlotLoader)3 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)2 MethodNode (org.codehaus.groovy.ast.MethodNode)2 CompileStack (org.codehaus.groovy.classgen.asm.CompileStack)2 Label (org.objectweb.asm.Label)2 MethodVisitor (org.objectweb.asm.MethodVisitor)2 ExpressionUtils.isSuperExpression (org.apache.groovy.ast.tools.ExpressionUtils.isSuperExpression)1 FieldNode (org.codehaus.groovy.ast.FieldNode)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 BinaryExpression (org.codehaus.groovy.ast.expr.BinaryExpression)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