Search in sources :

Example 61 with MethodVisitor

use of org.objectweb.asm.MethodVisitor 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) {
    ClassNode dynamicCallReturnType = origin.getNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION);
    if (dynamicCallReturnType != 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 (tryImplicitReceiver(origin, message, arguments, adapter, safe, spreadSafe, implicitThis)) {
        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 = new ConstructorCallExpression(StaticCompilationVisitor.ARRAYLIST_CLASSNODE, ArgumentListExpression.EMPTY_ARGUMENTS);
        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 = new VariableExpression(iterator);
        MethodCallExpression origMCE = (MethodCallExpression) origin;
        MethodCallExpression newMCE = new MethodCallExpression(iteratorAsVar, origMCE.getMethodAsString(), origMCE.getArguments());
        newMCE.setImplicitThis(false);
        newMCE.setMethodTarget(origMCE.getMethodTarget());
        newMCE.setSafe(true);
        MethodCallExpression add = new MethodCallExpression(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, new ExpressionStatement(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 = new MethodCallExpression(new VariableSlotLoader(slot.getType(), slot.getIndex(), controller.getOperandStack()), origMCE.getMethodAsString(), origMCE.getArguments());
        MethodNode methodTarget = origMCE.getMethodTarget();
        newMCE.setMethodTarget(methodTarget);
        newMCE.setSafe(false);
        newMCE.setImplicitThis(origMCE.isImplicitThis());
        newMCE.setSourcePosition(origMCE);
        newMCE.visit(controller.getAcg());
        compileStack.removeVar(slot.getIndex());
        ClassNode returnType = operandStack.getTopOperand();
        if (ClassHelper.isPrimitiveType(returnType) && !ClassHelper.VOID_TYPE.equals(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 ((adapter == AsmClassGenerator.getGroovyObjectField || adapter == AsmClassGenerator.getField) && origin instanceof AttributeExpression) {
            String pname = ((PropertyExpression) origin).getPropertyAsString();
            CallSiteWriter callSiteWriter = controller.getCallSiteWriter();
            if (pname != null && callSiteWriter instanceof StaticTypesCallSiteWriter) {
                StaticTypesCallSiteWriter stcsw = (StaticTypesCallSiteWriter) callSiteWriter;
                TypeChooser typeChooser = controller.getTypeChooser();
                if (stcsw.makeGetField(receiver, typeChooser.resolveType(receiver, controller.getClassNode()), pname, safe, false, true)) {
                    return;
                }
            }
        }
        super.makeCall(origin, receiver, message, arguments, adapter, safe, spreadSafe, implicitThis);
    }
}
Also used : Label(org.objectweb.asm.Label) MethodVisitor(org.objectweb.asm.MethodVisitor) ExtensionMethodNode(org.codehaus.groovy.transform.stc.ExtensionMethodNode) MethodNode(org.codehaus.groovy.ast.MethodNode) ForStatement(org.codehaus.groovy.ast.stmt.ForStatement) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) TemporaryVariableExpression(org.codehaus.groovy.transform.sc.TemporaryVariableExpression) TemporaryVariableExpression(org.codehaus.groovy.transform.sc.TemporaryVariableExpression) TemporaryVariableExpression(org.codehaus.groovy.transform.sc.TemporaryVariableExpression) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) Parameter(org.codehaus.groovy.ast.Parameter)

Example 62 with MethodVisitor

use of org.objectweb.asm.MethodVisitor in project groovy by apache.

the class StaticInvocationWriter method loadArguments.

protected void loadArguments(List<Expression> argumentList, Parameter[] para) {
    if (para.length == 0)
        return;
    ClassNode lastParaType = para[para.length - 1].getOriginType();
    AsmClassGenerator acg = controller.getAcg();
    TypeChooser typeChooser = controller.getTypeChooser();
    OperandStack operandStack = controller.getOperandStack();
    ClassNode lastArgType = !argumentList.isEmpty() ? typeChooser.resolveType(argumentList.get(argumentList.size() - 1), controller.getClassNode()) : null;
    if (lastParaType.isArray() && ((argumentList.size() > para.length) || ((argumentList.size() == (para.length - 1)) && !lastParaType.equals(lastArgType)) || ((argumentList.size() == para.length && lastArgType != null && !lastArgType.isArray()) && (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(lastArgType, lastParaType.getComponentType()))) || ClassHelper.GSTRING_TYPE.equals(lastArgType) && ClassHelper.STRING_TYPE.equals(lastParaType.getComponentType()))) {
        int stackLen = operandStack.getStackLength() + argumentList.size();
        MethodVisitor mv = controller.getMethodVisitor();
        //mv = new org.objectweb.asm.util.TraceMethodVisitor(mv);
        controller.setMethodVisitor(mv);
        // first parameters as usual
        for (int i = 0; i < para.length - 1; i++) {
            Expression expression = argumentList.get(i);
            expression.visit(acg);
            if (!isNullConstant(expression)) {
                operandStack.doGroovyCast(para[i].getType());
            }
        }
        // last parameters wrapped in an array
        List<Expression> lastParams = new LinkedList<Expression>();
        for (int i = para.length - 1; i < argumentList.size(); i++) {
            lastParams.add(argumentList.get(i));
        }
        ArrayExpression array = new ArrayExpression(lastParaType.getComponentType(), lastParams);
        array.visit(acg);
        // adjust stack length
        while (operandStack.getStackLength() < stackLen) {
            operandStack.push(ClassHelper.OBJECT_TYPE);
        }
        if (argumentList.size() == para.length - 1) {
            operandStack.remove(1);
        }
    } else if (argumentList.size() == para.length) {
        for (int i = 0; i < argumentList.size(); i++) {
            Expression expression = argumentList.get(i);
            expression.visit(acg);
            if (!isNullConstant(expression)) {
                operandStack.doGroovyCast(para[i].getType());
            }
        }
    } else {
        // method call with default arguments
        ClassNode classNode = controller.getClassNode();
        Expression[] arguments = new Expression[para.length];
        for (int i = 0, j = 0; i < para.length; i++) {
            Parameter curParam = para[i];
            ClassNode curParamType = curParam.getType();
            Expression curArg = j < argumentList.size() ? argumentList.get(j) : null;
            Expression initialExpression = (Expression) curParam.getNodeMetaData(StaticTypesMarker.INITIAL_EXPRESSION);
            if (initialExpression == null && curParam.hasInitialExpression())
                initialExpression = curParam.getInitialExpression();
            if (initialExpression == null && curParam.getNodeMetaData(Verifier.INITIAL_EXPRESSION) != null) {
                initialExpression = (Expression) curParam.getNodeMetaData(Verifier.INITIAL_EXPRESSION);
            }
            ClassNode curArgType = curArg == null ? null : typeChooser.resolveType(curArg, classNode);
            if (initialExpression != null && !compatibleArgumentType(curArgType, curParamType)) {
                // use default expression
                arguments[i] = initialExpression;
            } else {
                arguments[i] = curArg;
                j++;
            }
        }
        for (int i = 0; i < arguments.length; i++) {
            Expression expression = arguments[i];
            expression.visit(acg);
            if (!isNullConstant(expression)) {
                operandStack.doGroovyCast(para[i].getType());
            }
        }
    }
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) TemporaryVariableExpression(org.codehaus.groovy.transform.sc.TemporaryVariableExpression) Parameter(org.codehaus.groovy.ast.Parameter) AsmClassGenerator(org.codehaus.groovy.classgen.AsmClassGenerator) LinkedList(java.util.LinkedList) MethodVisitor(org.objectweb.asm.MethodVisitor)

Example 63 with MethodVisitor

use of org.objectweb.asm.MethodVisitor in project groovy by apache.

the class StaticTypesCallSiteWriter method makeGetPropertySite.

@Override
public void makeGetPropertySite(Expression receiver, final String methodName, final boolean safe, final boolean implicitThis) {
    Object dynamic = receiver.getNodeMetaData(StaticCompilationMetadataKeys.RECEIVER_OF_DYNAMIC_PROPERTY);
    if (dynamic != null) {
        makeDynamicGetProperty(receiver, methodName, safe);
        return;
    }
    TypeChooser typeChooser = controller.getTypeChooser();
    ClassNode classNode = controller.getClassNode();
    ClassNode receiverType = receiver.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
    if (receiverType == null) {
        receiverType = typeChooser.resolveType(receiver, classNode);
    }
    Object type = receiver.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
    if (type == null && receiver instanceof VariableExpression) {
        Variable variable = ((VariableExpression) receiver).getAccessedVariable();
        if (variable instanceof Expression) {
            type = ((Expression) variable).getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
        }
    }
    if (type != null) {
        // in case a "flow type" is found, it is preferred to use it instead of
        // the declaration type
        receiverType = (ClassNode) type;
    }
    boolean isClassReceiver = false;
    if (isClassClassNodeWrappingConcreteType(receiverType)) {
        isClassReceiver = true;
        receiverType = receiverType.getGenericsTypes()[0].getType();
    }
    if (isPrimitiveType(receiverType)) {
        // GROOVY-6590: wrap primitive types
        receiverType = getWrapper(receiverType);
    }
    MethodVisitor mv = controller.getMethodVisitor();
    if (receiverType.isArray() && methodName.equals("length")) {
        receiver.visit(controller.getAcg());
        ClassNode arrayGetReturnType = typeChooser.resolveType(receiver, classNode);
        controller.getOperandStack().doGroovyCast(arrayGetReturnType);
        mv.visitInsn(ARRAYLENGTH);
        controller.getOperandStack().replace(int_TYPE);
        return;
    } else if ((receiverType.implementsInterface(COLLECTION_TYPE) || COLLECTION_TYPE.equals(receiverType)) && ("size".equals(methodName) || "length".equals(methodName))) {
        MethodCallExpression expr = new MethodCallExpression(receiver, "size", ArgumentListExpression.EMPTY_ARGUMENTS);
        expr.setMethodTarget(COLLECTION_SIZE_METHOD);
        expr.setImplicitThis(implicitThis);
        expr.setSafe(safe);
        expr.visit(controller.getAcg());
        return;
    }
    if (makeGetPropertyWithGetter(receiver, receiverType, methodName, safe, implicitThis))
        return;
    if (makeGetField(receiver, receiverType, methodName, safe, implicitThis, samePackages(receiverType.getPackageName(), classNode.getPackageName())))
        return;
    if (receiverType.isEnum()) {
        mv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(receiverType), methodName, BytecodeHelper.getTypeDescription(receiverType));
        controller.getOperandStack().push(receiverType);
        return;
    }
    if (receiver instanceof ClassExpression) {
        if (makeGetField(receiver, receiver.getType(), methodName, safe, implicitThis, samePackages(receiver.getType().getPackageName(), classNode.getPackageName())))
            return;
        if (makeGetPropertyWithGetter(receiver, receiver.getType(), methodName, safe, implicitThis))
            return;
        if (makeGetPrivateFieldWithBridgeMethod(receiver, receiver.getType(), methodName, safe, implicitThis))
            return;
    }
    if (isClassReceiver) {
        // we are probably looking for a property of the class
        if (makeGetPropertyWithGetter(receiver, CLASS_Type, methodName, safe, implicitThis))
            return;
        if (makeGetField(receiver, CLASS_Type, methodName, safe, false, true))
            return;
    }
    if (makeGetPrivateFieldWithBridgeMethod(receiver, receiverType, methodName, safe, implicitThis))
        return;
    // GROOVY-5580, it is still possible that we're calling a superinterface property
    String getterName = "get" + MetaClassHelper.capitalize(methodName);
    String altGetterName = "is" + MetaClassHelper.capitalize(methodName);
    if (receiverType.isInterface()) {
        Set<ClassNode> allInterfaces = receiverType.getAllInterfaces();
        MethodNode getterMethod = null;
        for (ClassNode anInterface : allInterfaces) {
            getterMethod = anInterface.getGetterMethod(getterName);
            if (getterMethod == null)
                getterMethod = anInterface.getGetterMethod(altGetterName);
            if (getterMethod != null)
                break;
        }
        // GROOVY-5585
        if (getterMethod == null) {
            getterMethod = OBJECT_TYPE.getGetterMethod(getterName);
        }
        if (getterMethod != null) {
            MethodCallExpression call = new MethodCallExpression(receiver, getterName, ArgumentListExpression.EMPTY_ARGUMENTS);
            call.setMethodTarget(getterMethod);
            call.setImplicitThis(false);
            call.setSourcePosition(receiver);
            call.setSafe(safe);
            call.visit(controller.getAcg());
            return;
        }
    }
    // GROOVY-5568, we would be facing a DGM call, but instead of foo.getText(), have foo.text
    List<MethodNode> methods = findDGMMethodsByNameAndArguments(controller.getSourceUnit().getClassLoader(), receiverType, getterName, ClassNode.EMPTY_ARRAY);
    for (MethodNode m : findDGMMethodsByNameAndArguments(controller.getSourceUnit().getClassLoader(), receiverType, altGetterName, ClassNode.EMPTY_ARRAY)) {
        if (Boolean_TYPE.equals(getWrapper(m.getReturnType())))
            methods.add(m);
    }
    if (!methods.isEmpty()) {
        List<MethodNode> methodNodes = chooseBestMethod(receiverType, methods, ClassNode.EMPTY_ARRAY);
        if (methodNodes.size() == 1) {
            MethodNode getter = methodNodes.get(0);
            MethodCallExpression call = new MethodCallExpression(receiver, getter.getName(), ArgumentListExpression.EMPTY_ARGUMENTS);
            call.setMethodTarget(getter);
            call.setImplicitThis(false);
            call.setSafe(safe);
            call.setSourcePosition(receiver);
            call.visit(controller.getAcg());
            return;
        }
    }
    boolean isStaticProperty = receiver instanceof ClassExpression && (receiverType.isDerivedFrom(receiver.getType()) || receiverType.implementsInterface(receiver.getType()));
    if (!isStaticProperty) {
        if (receiverType.implementsInterface(MAP_TYPE) || MAP_TYPE.equals(receiverType)) {
            // for maps, replace map.foo with map.get('foo')
            writeMapDotProperty(receiver, methodName, mv, safe);
            return;
        }
        if (receiverType.implementsInterface(LIST_TYPE) || LIST_TYPE.equals(receiverType)) {
            writeListDotProperty(receiver, methodName, mv, safe);
            return;
        }
    }
    controller.getSourceUnit().addError(new SyntaxException("Access to " + (receiver instanceof ClassExpression ? receiver.getType() : receiverType).toString(false) + "#" + methodName + " is forbidden", receiver.getLineNumber(), receiver.getColumnNumber(), receiver.getLastLineNumber(), receiver.getLastColumnNumber()));
    controller.getMethodVisitor().visitInsn(ACONST_NULL);
    controller.getOperandStack().push(OBJECT_TYPE);
}
Also used : MethodVisitor(org.objectweb.asm.MethodVisitor) BytecodeExpression(org.codehaus.groovy.classgen.BytecodeExpression) SyntaxException(org.codehaus.groovy.syntax.SyntaxException)

Example 64 with MethodVisitor

use of org.objectweb.asm.MethodVisitor in project groovy by apache.

the class StaticTypesCallSiteWriter method writeOperatorCall.

private void writeOperatorCall(Expression receiver, Expression arguments, String operator) {
    prepareSiteAndReceiver(receiver, operator, false, controller.getCompileStack().isLHS());
    controller.getOperandStack().doGroovyCast(Number_TYPE);
    visitBoxedArgument(arguments);
    controller.getOperandStack().doGroovyCast(Number_TYPE);
    MethodVisitor mv = controller.getMethodVisitor();
    mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/typehandling/NumberMath", operator, "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;", false);
    controller.getOperandStack().replace(Number_TYPE, 2);
}
Also used : MethodVisitor(org.objectweb.asm.MethodVisitor)

Example 65 with MethodVisitor

use of org.objectweb.asm.MethodVisitor in project groovy by apache.

the class StaticTypesCallSiteWriter method writePowerCall.

private void writePowerCall(Expression receiver, Expression arguments, final ClassNode rType, ClassNode aType) {
    OperandStack operandStack = controller.getOperandStack();
    int m1 = operandStack.getStackLength();
    //slow Path
    prepareSiteAndReceiver(receiver, "power", false, controller.getCompileStack().isLHS());
    operandStack.doGroovyCast(getWrapper(rType));
    visitBoxedArgument(arguments);
    operandStack.doGroovyCast(getWrapper(aType));
    int m2 = operandStack.getStackLength();
    MethodVisitor mv = controller.getMethodVisitor();
    if (BigDecimal_TYPE.equals(rType) && Integer_TYPE.equals(getWrapper(aType))) {
        mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/math/BigDecimal;Ljava/lang/Integer;)Ljava/lang/Number;", false);
    } else if (BigInteger_TYPE.equals(rType) && Integer_TYPE.equals(getWrapper(aType))) {
        mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/math/BigInteger;Ljava/lang/Integer;)Ljava/lang/Number;", false);
    } else if (Long_TYPE.equals(getWrapper(rType)) && Integer_TYPE.equals(getWrapper(aType))) {
        mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/lang/Long;Ljava/lang/Integer;)Ljava/lang/Number;", false);
    } else if (Integer_TYPE.equals(getWrapper(rType)) && Integer_TYPE.equals(getWrapper(aType))) {
        mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Number;", false);
    } else {
        mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;", false);
    }
    controller.getOperandStack().replace(Number_TYPE, m2 - m1);
}
Also used : MethodVisitor(org.objectweb.asm.MethodVisitor)

Aggregations

MethodVisitor (org.objectweb.asm.MethodVisitor)630 Label (org.objectweb.asm.Label)186 ClassWriter (org.objectweb.asm.ClassWriter)116 Type (org.objectweb.asm.Type)59 ClassNode (org.codehaus.groovy.ast.ClassNode)57 FieldVisitor (org.objectweb.asm.FieldVisitor)56 ClassVisitor (org.objectweb.asm.ClassVisitor)47 ClassReader (org.objectweb.asm.ClassReader)43 ArrayList (java.util.ArrayList)32 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)30 Test (org.junit.Test)29 AnnotationVisitor (org.objectweb.asm.AnnotationVisitor)29 List (java.util.List)23 LinkedList (java.util.LinkedList)22 Parameter (org.codehaus.groovy.ast.Parameter)22 InterfaceHelperClassNode (org.codehaus.groovy.ast.InterfaceHelperClassNode)18 AsmClassGenerator (org.codehaus.groovy.classgen.AsmClassGenerator)18 BytecodeExpression (org.codehaus.groovy.classgen.BytecodeExpression)18 ArgumentListExpression (org.codehaus.groovy.ast.expr.ArgumentListExpression)17 Method (java.lang.reflect.Method)16