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;
}
});
}
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");
}
}
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;
}
});
}
}
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();
}
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;
}
});
}
Aggregations