Search in sources :

Example 16 with InstructionAdapter

use of org.jetbrains.org.objectweb.asm.commons.InstructionAdapter in project kotlin by JetBrains.

the class ExpressionCodegen method generateWhenExpression.

public StackValue generateWhenExpression(final KtWhenExpression expression, final boolean isStatement) {
    final KtExpression expr = expression.getSubjectExpression();
    final Type subjectType = expressionType(expr);
    final Type resultType = isStatement ? Type.VOID_TYPE : expressionTypeForBranchingOperation(expression);
    return StackValue.operation(resultType, new Function1<InstructionAdapter, Unit>() {

        @Override
        public Unit invoke(InstructionAdapter v) {
            SwitchCodegen switchCodegen = SwitchCodegenUtil.buildAppropriateSwitchCodegenIfPossible(expression, isStatement, CodegenUtil.isExhaustive(bindingContext, expression, isStatement), ExpressionCodegen.this);
            if (switchCodegen != null) {
                switchCodegen.generate();
                return Unit.INSTANCE;
            }
            int subjectLocal = expr != null ? myFrameMap.enterTemp(subjectType) : -1;
            if (subjectLocal != -1) {
                gen(expr, subjectType);
                tempVariables.put(expr, StackValue.local(subjectLocal, subjectType));
                v.store(subjectLocal, subjectType);
            }
            Label end = new Label();
            boolean hasElse = KtPsiUtil.checkWhenExpressionHasSingleElse(expression);
            Label nextCondition = null;
            for (KtWhenEntry whenEntry : expression.getEntries()) {
                if (nextCondition != null) {
                    v.mark(nextCondition);
                }
                nextCondition = new Label();
                FrameMap.Mark mark = myFrameMap.mark();
                Label thisEntry = new Label();
                if (!whenEntry.isElse()) {
                    KtWhenCondition[] conditions = whenEntry.getConditions();
                    for (int i = 0; i < conditions.length; i++) {
                        StackValue conditionValue = generateWhenCondition(expr, subjectType, subjectLocal, conditions[i]);
                        BranchedValue.Companion.condJump(conditionValue, nextCondition, true, v);
                        if (i < conditions.length - 1) {
                            v.goTo(thisEntry);
                            v.mark(nextCondition);
                            nextCondition = new Label();
                        }
                    }
                }
                v.visitLabel(thisEntry);
                gen(whenEntry.getExpression(), resultType);
                mark.dropTo();
                if (!whenEntry.isElse()) {
                    v.goTo(end);
                }
            }
            if (!hasElse && nextCondition != null) {
                v.mark(nextCondition);
                putUnitInstanceOntoStackForNonExhaustiveWhen(expression, isStatement);
            }
            markLineNumber(expression, isStatement);
            v.mark(end);
            myFrameMap.leaveTemp(subjectType);
            tempVariables.remove(expr);
            return null;
        }
    });
}
Also used : IElementType(com.intellij.psi.tree.IElementType) Type(org.jetbrains.org.objectweb.asm.Type) KotlinType(org.jetbrains.kotlin.types.KotlinType) InstructionAdapter(org.jetbrains.org.objectweb.asm.commons.InstructionAdapter) Label(org.jetbrains.org.objectweb.asm.Label) Unit(kotlin.Unit) SwitchCodegen(org.jetbrains.kotlin.codegen.when.SwitchCodegen)

Example 17 with InstructionAdapter

use of org.jetbrains.org.objectweb.asm.commons.InstructionAdapter in project kotlin by JetBrains.

the class SamWrapperCodegen method generateConstructor.

private void generateConstructor(Type ownerType, Type functionType, ClassBuilder cv) {
    MethodVisitor mv = cv.newMethod(JvmDeclarationOriginKt.OtherOrigin(samType.getJavaClassDescriptor()), visibility, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, functionType), null, null);
    if (state.getClassBuilderMode().generateBodies) {
        mv.visitCode();
        InstructionAdapter iv = new InstructionAdapter(mv);
        // super constructor
        iv.load(0, OBJECT_TYPE);
        iv.invokespecial(OBJECT_TYPE.getInternalName(), "<init>", "()V", false);
        // save parameter to field
        iv.load(0, OBJECT_TYPE);
        iv.load(1, functionType);
        iv.putfield(ownerType.getInternalName(), FUNCTION_FIELD_NAME, functionType.getDescriptor());
        iv.visitInsn(RETURN);
        FunctionCodegen.endVisit(iv, "constructor of SAM wrapper");
    }
}
Also used : InstructionAdapter(org.jetbrains.org.objectweb.asm.commons.InstructionAdapter) MethodVisitor(org.jetbrains.org.objectweb.asm.MethodVisitor)

Example 18 with InstructionAdapter

use of org.jetbrains.org.objectweb.asm.commons.InstructionAdapter in project kotlin by JetBrains.

the class ExpressionCodegen method visitStringTemplateExpression.

@Override
public StackValue visitStringTemplateExpression(@NotNull KtStringTemplateExpression expression, StackValue receiver) {
    StringBuilder constantValue = new StringBuilder("");
    final KtStringTemplateEntry[] entries = expression.getEntries();
    if (entries.length == 1 && entries[0] instanceof KtStringTemplateEntryWithExpression) {
        KtExpression expr = entries[0].getExpression();
        return genToString(gen(expr), expressionType(expr));
    }
    for (KtStringTemplateEntry entry : entries) {
        if (entry instanceof KtLiteralStringTemplateEntry) {
            constantValue.append(entry.getText());
        } else if (entry instanceof KtEscapeStringTemplateEntry) {
            constantValue.append(((KtEscapeStringTemplateEntry) entry).getUnescapedValue());
        } else {
            constantValue = null;
            break;
        }
    }
    if (constantValue != null) {
        Type type = expressionType(expression);
        return StackValue.constant(constantValue.toString(), type);
    } else {
        return StackValue.operation(JAVA_STRING_TYPE, new Function1<InstructionAdapter, Unit>() {

            @Override
            public Unit invoke(InstructionAdapter v) {
                genStringBuilderConstructor(v);
                for (KtStringTemplateEntry entry : entries) {
                    if (entry instanceof KtStringTemplateEntryWithExpression) {
                        invokeAppend(entry.getExpression());
                    } else {
                        String text = entry instanceof KtEscapeStringTemplateEntry ? ((KtEscapeStringTemplateEntry) entry).getUnescapedValue() : entry.getText();
                        v.aconst(text);
                        genInvokeAppendMethod(v, JAVA_STRING_TYPE);
                    }
                }
                v.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
                return Unit.INSTANCE;
            }
        });
    }
}
Also used : Unit(kotlin.Unit) IElementType(com.intellij.psi.tree.IElementType) Type(org.jetbrains.org.objectweb.asm.Type) KotlinType(org.jetbrains.kotlin.types.KotlinType) InstructionAdapter(org.jetbrains.org.objectweb.asm.commons.InstructionAdapter)

Example 19 with InstructionAdapter

use of org.jetbrains.org.objectweb.asm.commons.InstructionAdapter in project kotlin by JetBrains.

the class InterceptionInstrumenter method instrument.

private byte[] instrument(byte[] classData, final List<MethodInstrumenter> instrumenters) {
    final ClassReader cr = new ClassReader(classData);
    ClassWriter cw = new ClassWriter(cr, 0);
    cr.accept(new ClassVisitor(ASM5, cw) {

        private final Map<MethodInstrumenter, String> matchedMethods = new HashMap<MethodInstrumenter, String>();

        @Override
        public MethodVisitor visitMethod(final int access, final String name, final String desc, String signature, String[] exceptions) {
            MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
            // Do not instrument synthetic methods
            if ((access & (ACC_BRIDGE | ACC_SYNTHETIC)) != 0)
                return mv;
            List<MethodInstrumenter> applicableInstrumenters = new ArrayList<MethodInstrumenter>();
            for (MethodInstrumenter instrumenter : instrumenters) {
                if (instrumenter.isApplicable(name, desc)) {
                    applicableInstrumenters.add(instrumenter);
                    instrumenter.reportApplication(cr.getClassName(), name, desc);
                    checkMultipleMatches(instrumenter, name, desc);
                    neverMatchedInstrumenters.remove(instrumenter);
                }
            }
            if (applicableInstrumenters.isEmpty())
                return mv;
            boolean dumpByteCode = false;
            final List<MethodData> normalReturnData = new ArrayList<MethodData>();
            final List<MethodData> enterData = new ArrayList<MethodData>();
            final List<MethodData> exceptionData = new ArrayList<MethodData>();
            for (MethodInstrumenter instrumenter : applicableInstrumenters) {
                enterData.addAll(instrumenter.getEnterData());
                normalReturnData.addAll(instrumenter.getNormalReturnData());
                exceptionData.addAll(instrumenter.getExceptionData());
                dumpByteCode |= instrumenter.shouldDumpByteCode();
            }
            if (enterData.isEmpty() && normalReturnData.isEmpty() && exceptionData.isEmpty())
                return mv;
            if (dumpByteCode) {
                mv = getDumpingVisitorWrapper(mv, name, desc);
            }
            final int maxStackDepth = getMaxStackDepth(name, desc, normalReturnData, enterData, exceptionData);
            final boolean isConstructor = "<init>".equals(name);
            return new MethodVisitor(ASM5, mv) {

                private InstructionAdapter ia = null;

                private InstructionAdapter getInstructionAdapter() {
                    if (ia == null) {
                        ia = new InstructionAdapter(this);
                    }
                    return ia;
                }

                @Override
                public void visitMaxs(int maxStack, int maxLocals) {
                    super.visitMaxs(Math.max(maxStack, maxStackDepth), maxLocals);
                }

                @Override
                public void visitCode() {
                    for (MethodData methodData : enterData) {
                        // At the very beginning of a constructor, i.e. before any super() call, 'this' is not available
                        // It's too hard to detect a place right after the super() call, so we just put null instead of 'this' in such cases
                        invokeMethod(access, cr.getClassName(), name, desc, getInstructionAdapter(), methodData, isConstructor);
                    }
                    super.visitCode();
                }

                @Override
                public void visitInsn(int opcode) {
                    switch(opcode) {
                        case RETURN:
                        case IRETURN:
                        case LRETURN:
                        case FRETURN:
                        case DRETURN:
                        case ARETURN:
                            for (MethodData methodData : normalReturnData) {
                                invokeMethod(access, cr.getClassName(), name, desc, getInstructionAdapter(), methodData, false);
                            }
                            break;
                        case ATHROW:
                            for (MethodData methodData : exceptionData) {
                                // A constructor may throw before calling super(), 'this' is not available in this case
                                invokeMethod(access, cr.getClassName(), name, desc, getInstructionAdapter(), methodData, isConstructor);
                            }
                            break;
                    }
                    super.visitInsn(opcode);
                }
            };
        }

        private int getMaxStackDepth(String name, String desc, List<MethodData> normalReturnData, List<MethodData> enterData, List<MethodData> exceptionData) {
            org.jetbrains.org.objectweb.asm.commons.Method methodBeingInstrumented = new org.jetbrains.org.objectweb.asm.commons.Method(name, desc);
            List<MethodData> allData = new ArrayList<MethodData>();
            allData.addAll(enterData);
            allData.addAll(exceptionData);
            allData.addAll(normalReturnData);
            int maxStackDepth = 0;
            for (MethodData methodData : allData) {
                int depth = stackDepth(methodData, methodBeingInstrumented);
                if (maxStackDepth < depth) {
                    maxStackDepth = depth;
                }
            }
            return maxStackDepth;
        }

        private int stackDepth(MethodData methodData, org.jetbrains.org.objectweb.asm.commons.Method methodBeingInstrumented) {
            org.jetbrains.org.objectweb.asm.commons.Method method = getAsmMethod(methodData);
            // array * 2 (dup) + index + value (may be long/double)
            int allArgsStackDepth = methodData.getAllArgsParameterIndex() >= 0 ? 5 : 0;
            int argsSize = 0;
            for (Type type : method.getArgumentTypes()) {
                argsSize += type.getSize();
            }
            int receiverSize = 1;
            // return value must be kept on the stack OR exception, so we have to reserve at least 1
            int exceptionSize = 1;
            int returnValueSize = methodBeingInstrumented.getReturnType().getSize();
            return argsSize + allArgsStackDepth + receiverSize + Math.max(returnValueSize, exceptionSize);
        }

        private void checkMultipleMatches(MethodInstrumenter instrumenter, String name, String desc) {
            if (!instrumenter.allowsMultipleMatches()) {
                String erasedSignature = name + desc;
                String alreadyMatched = matchedMethods.put(instrumenter, erasedSignature);
                if (alreadyMatched != null) {
                    throw new IllegalStateException(instrumenter + " matched two methods in " + cr.getClassName() + ":\n" + alreadyMatched + "\n" + erasedSignature);
                }
            }
        }

        private TraceMethodVisitor getDumpingVisitorWrapper(MethodVisitor mv, final String methodName, final String methodDesc) {
            return new TraceMethodVisitor(mv, new Textifier(ASM5) {

                @Override
                public void visitMethodEnd() {
                    System.out.println(cr.getClassName() + ":" + methodName + methodDesc);
                    for (Object line : getText()) {
                        System.out.print(line);
                    }
                    System.out.println();
                    System.out.println();
                    super.visitMethodEnd();
                }
            });
        }
    }, 0);
    return cw.toByteArray();
}
Also used : Textifier(org.jetbrains.org.objectweb.asm.util.Textifier) TraceMethodVisitor(org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor) Method(java.lang.reflect.Method) TraceMethodVisitor(org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor) InstructionAdapter(org.jetbrains.org.objectweb.asm.commons.InstructionAdapter) org.jetbrains.org.objectweb.asm(org.jetbrains.org.objectweb.asm)

Example 20 with InstructionAdapter

use of org.jetbrains.org.objectweb.asm.commons.InstructionAdapter in project kotlin by JetBrains.

the class AsmUtil method genEqualsForExpressionsOnStack.

@NotNull
public static StackValue genEqualsForExpressionsOnStack(@NotNull final IElementType opToken, @NotNull final StackValue left, @NotNull final StackValue right) {
    final Type leftType = left.type;
    final Type rightType = right.type;
    if (isPrimitive(leftType) && leftType == rightType) {
        return StackValue.cmp(opToken, leftType, left, right);
    }
    return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() {

        @Override
        public Unit invoke(InstructionAdapter v) {
            left.put(leftType, v);
            right.put(rightType, v);
            genAreEqualCall(v);
            if (opToken == KtTokens.EXCLEQ || opToken == KtTokens.EXCLEQEQEQ) {
                genInvertBoolean(v);
            }
            return Unit.INSTANCE;
        }
    });
}
Also used : IElementType(com.intellij.psi.tree.IElementType) JvmPrimitiveType(org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType) PrimitiveType(org.jetbrains.kotlin.builtins.PrimitiveType) KotlinType(org.jetbrains.kotlin.types.KotlinType) TypeUtils.isNullableType(org.jetbrains.kotlin.types.TypeUtils.isNullableType) InstructionAdapter(org.jetbrains.org.objectweb.asm.commons.InstructionAdapter) Unit(kotlin.Unit) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

InstructionAdapter (org.jetbrains.org.objectweb.asm.commons.InstructionAdapter)35 KotlinType (org.jetbrains.kotlin.types.KotlinType)23 Type (org.jetbrains.org.objectweb.asm.Type)16 IElementType (com.intellij.psi.tree.IElementType)10 Unit (kotlin.Unit)10 MethodVisitor (org.jetbrains.org.objectweb.asm.MethodVisitor)7 Label (org.jetbrains.org.objectweb.asm.Label)5 Method (org.jetbrains.org.objectweb.asm.commons.Method)5 JavaClassDescriptor (org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor)4 NotNull (org.jetbrains.annotations.NotNull)3 Type.getObjectType (org.jetbrains.org.objectweb.asm.Type.getObjectType)3 Nullable (org.jetbrains.annotations.Nullable)2 PrimitiveType (org.jetbrains.kotlin.builtins.PrimitiveType)2 JvmPrimitiveType (org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType)2 JvmMethodSignature (org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature)2 TypeUtils.isNullableType (org.jetbrains.kotlin.types.TypeUtils.isNullableType)2 TraceMethodVisitor (org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor)2 Method (java.lang.reflect.Method)1 KotlinBuiltIns (org.jetbrains.kotlin.builtins.KotlinBuiltIns)1 AsmUtil.getVisibilityForBackingField (org.jetbrains.kotlin.codegen.AsmUtil.getVisibilityForBackingField)1