use of org.jetbrains.org.objectweb.asm.MethodVisitor in project kotlin by JetBrains.
the class ClosureCodegen method generateConstructor.
@NotNull
protected Method generateConstructor() {
List<FieldInfo> args = calculateConstructorParameters(typeMapper, closure, asmType);
Type[] argTypes = fieldListToTypeArray(args);
Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes);
MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(element, funDescriptor), visibilityFlag, "<init>", constructor.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY);
if (state.getClassBuilderMode().generateBodies) {
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
Pair<Integer, Type> receiverIndexAndType = CallableReferenceUtilKt.generateClosureFieldsInitializationFromParameters(iv, closure, args);
if (shouldHaveBoundReferenceReceiver && receiverIndexAndType == null) {
throw new AssertionError("No bound reference receiver in constructor parameters: " + args);
}
int boundReferenceReceiverParameterIndex = shouldHaveBoundReferenceReceiver ? receiverIndexAndType.getFirst() : -1;
Type boundReferenceReceiverType = shouldHaveBoundReferenceReceiver ? receiverIndexAndType.getSecond() : null;
iv.load(0, superClassAsmType);
String superClassConstructorDescriptor;
if (superClassAsmType.equals(LAMBDA) || superClassAsmType.equals(FUNCTION_REFERENCE) || superClassAsmType.equals(CoroutineCodegenUtilKt.COROUTINE_IMPL_ASM_TYPE)) {
int arity = calculateArity();
iv.iconst(arity);
if (shouldHaveBoundReferenceReceiver) {
CallableReferenceUtilKt.loadBoundReferenceReceiverParameter(iv, boundReferenceReceiverParameterIndex, boundReferenceReceiverType);
superClassConstructorDescriptor = "(ILjava/lang/Object;)V";
} else {
superClassConstructorDescriptor = "(I)V";
}
} else {
assert !shouldHaveBoundReferenceReceiver : "Unexpected bound reference with supertype " + superClassAsmType;
superClassConstructorDescriptor = "()V";
}
iv.invokespecial(superClassAsmType.getInternalName(), "<init>", superClassConstructorDescriptor, false);
iv.visitInsn(RETURN);
FunctionCodegen.endVisit(iv, "constructor", element);
}
return constructor;
}
use of org.jetbrains.org.objectweb.asm.MethodVisitor in project kotlin by JetBrains.
the class ClosureCodegen method generateBridge.
protected void generateBridge(@NotNull Method bridge, @NotNull Method delegate) {
if (bridge.equals(delegate))
return;
MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(element, funDescriptor), ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC, bridge.getName(), bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY);
if (!state.getClassBuilderMode().generateBodies)
return;
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
MemberCodegen.markLineNumberForDescriptor(DescriptorUtils.getParentOfType(funDescriptor, ClassDescriptor.class), iv);
iv.load(0, asmType);
Type[] myParameterTypes = bridge.getArgumentTypes();
List<ParameterDescriptor> calleeParameters = CollectionsKt.plus(org.jetbrains.kotlin.utils.CollectionsKt.<ParameterDescriptor>singletonOrEmptyList(funDescriptor.getExtensionReceiverParameter()), funDescriptor.getValueParameters());
int slot = 1;
for (int i = 0; i < calleeParameters.size(); i++) {
Type type = myParameterTypes[i];
StackValue.local(slot, type).put(typeMapper.mapType(calleeParameters.get(i)), iv);
slot += type.getSize();
}
iv.invokevirtual(asmType.getInternalName(), delegate.getName(), delegate.getDescriptor(), false);
StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), iv);
iv.areturn(bridge.getReturnType());
FunctionCodegen.endVisit(mv, "bridge", element);
}
use of org.jetbrains.org.objectweb.asm.MethodVisitor in project intellij-community by JetBrains.
the class MethodBreakpoint method createRequestForPreparedClassEmulated.
static void createRequestForPreparedClassEmulated(@NotNull MethodBreakpointBase breakpoint, @NotNull DebugProcessImpl debugProcess, @NotNull ReferenceType classType, boolean base) {
if (!base && !shouldCreateRequest(breakpoint, breakpoint.getXBreakpoint(), debugProcess, true)) {
return;
}
try {
Method lambdaMethod = MethodBytecodeUtil.getLambdaMethod(classType, debugProcess.getVirtualMachineProxy());
StreamEx<Method> methods = lambdaMethod != null ? StreamEx.of(lambdaMethod) : breakpoint.matchingMethods(StreamEx.of(classType.methods()).filter(m -> base || !m.isAbstract()), debugProcess);
boolean found = false;
for (Method method : methods) {
found = true;
if (base && method.isNative()) {
breakpoint.disableEmulation();
return;
}
Method target = MethodBytecodeUtil.getBridgeTargetMethod(method, debugProcess.getVirtualMachineProxy());
if (target != null && !DebuggerUtilsEx.allLineLocations(target).isEmpty()) {
method = target;
}
List<Location> allLineLocations = DebuggerUtilsEx.allLineLocations(method);
if (!allLineLocations.isEmpty()) {
if (breakpoint.isWatchEntry()) {
createLocationBreakpointRequest(breakpoint, ContainerUtil.getFirstItem(allLineLocations), debugProcess);
}
if (breakpoint.isWatchExit()) {
MethodBytecodeUtil.visit(method, new MethodVisitor(Opcodes.API_VERSION) {
int myLastLine = 0;
@Override
public void visitLineNumber(int line, Label start) {
myLastLine = line;
}
@Override
public void visitInsn(int opcode) {
switch(opcode) {
case Opcodes.RETURN:
case Opcodes.IRETURN:
case Opcodes.FRETURN:
case Opcodes.ARETURN:
case Opcodes.LRETURN:
case Opcodes.DRETURN:
//case Opcodes.ATHROW:
allLineLocations.stream().filter(l -> l.lineNumber() == myLastLine).findFirst().ifPresent(location -> createLocationBreakpointRequest(breakpoint, location, debugProcess));
}
}
}, true);
}
}
}
if (base && found) {
// desired class found - now also track all new classes
createRequestForSubClasses(breakpoint, debugProcess, classType);
}
} catch (Exception e) {
LOG.debug(e);
}
}
use of org.jetbrains.org.objectweb.asm.MethodVisitor in project intellij-community by JetBrains.
the class JavaSmartStepIntoHandler method findSmartStepTargets.
protected List<SmartStepTarget> findSmartStepTargets(final SourcePosition position, @Nullable SuspendContextImpl suspendContext, @NotNull DebuggerContextImpl debuggerContext) {
final int line = position.getLine();
if (line < 0) {
// the document has been changed
return Collections.emptyList();
}
final PsiFile file = position.getFile();
final VirtualFile vFile = file.getVirtualFile();
if (vFile == null) {
// the file is not physical
return Collections.emptyList();
}
final Document doc = FileDocumentManager.getInstance().getDocument(vFile);
if (doc == null)
return Collections.emptyList();
if (line >= doc.getLineCount()) {
// the document has been changed
return Collections.emptyList();
}
TextRange curLineRange = DocumentUtil.getLineTextRange(doc, line);
PsiElement element = position.getElementAt();
PsiElement body = DebuggerUtilsEx.getBody(DebuggerUtilsEx.getContainingMethod(element));
final TextRange lineRange = (body != null) ? curLineRange.intersection(body.getTextRange()) : curLineRange;
if (lineRange == null || lineRange.isEmpty()) {
return Collections.emptyList();
}
if (element != null && !(element instanceof PsiCompiledElement)) {
do {
final PsiElement parent = element.getParent();
if (parent == null || (parent.getTextOffset() < lineRange.getStartOffset())) {
break;
}
element = parent;
} while (true);
//noinspection unchecked
final List<SmartStepTarget> targets = new OrderedSet<>();
final Ref<TextRange> textRange = new Ref<>(lineRange);
final PsiElementVisitor methodCollector = new JavaRecursiveElementVisitor() {
final Deque<PsiMethod> myContextStack = new LinkedList<>();
final Deque<String> myParamNameStack = new LinkedList<>();
private int myNextLambdaExpressionOrdinal = 0;
private boolean myInsideLambda = false;
@Nullable
private String getCurrentParamName() {
return myParamNameStack.peekFirst();
}
@Override
public void visitAnonymousClass(PsiAnonymousClass aClass) {
for (PsiMethod psiMethod : aClass.getMethods()) {
targets.add(0, new MethodSmartStepTarget(psiMethod, getCurrentParamName(), psiMethod.getBody(), true, null));
}
}
public void visitLambdaExpression(PsiLambdaExpression expression) {
boolean inLambda = myInsideLambda;
myInsideLambda = true;
super.visitLambdaExpression(expression);
myInsideLambda = inLambda;
targets.add(0, new LambdaSmartStepTarget(expression, getCurrentParamName(), expression.getBody(), myNextLambdaExpressionOrdinal++, null, !myInsideLambda));
}
@Override
public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) {
PsiElement element = expression.resolve();
if (element instanceof PsiMethod) {
PsiElement navMethod = element.getNavigationElement();
if (navMethod instanceof PsiMethod) {
targets.add(0, new MethodSmartStepTarget(((PsiMethod) navMethod), null, expression, true, null));
}
}
}
@Override
public void visitField(PsiField field) {
if (checkTextRange(field, false)) {
super.visitField(field);
}
}
@Override
public void visitMethod(PsiMethod method) {
if (checkTextRange(method, false)) {
super.visitMethod(method);
}
}
@Override
public void visitStatement(PsiStatement statement) {
if (checkTextRange(statement, true)) {
super.visitStatement(statement);
}
}
@Override
public void visitIfStatement(PsiIfStatement statement) {
visitConditional(statement.getCondition(), statement.getThenBranch(), statement.getElseBranch());
}
@Override
public void visitConditionalExpression(PsiConditionalExpression expression) {
visitConditional(expression.getCondition(), expression.getThenExpression(), expression.getElseExpression());
}
private void visitConditional(@Nullable PsiElement condition, @Nullable PsiElement thenBranch, @Nullable PsiElement elseBranch) {
if (condition != null && checkTextRange(condition, true)) {
condition.accept(this);
}
ThreeState conditionRes = evaluateCondition(condition);
if (conditionRes != ThreeState.NO && thenBranch != null && checkTextRange(thenBranch, true)) {
thenBranch.accept(this);
}
if (conditionRes != ThreeState.YES && elseBranch != null && checkTextRange(elseBranch, true)) {
elseBranch.accept(this);
}
}
private ThreeState evaluateCondition(@Nullable PsiElement condition) {
if (condition != null && !DebuggerUtils.hasSideEffects(condition)) {
try {
ExpressionEvaluator evaluator = EvaluatorBuilderImpl.getInstance().build(condition, position);
return ThreeState.fromBoolean(DebuggerUtilsEx.evaluateBoolean(evaluator, debuggerContext.createEvaluationContext()));
} catch (EvaluateException e) {
LOG.info(e);
}
}
return ThreeState.UNSURE;
}
@Override
public void visitExpression(PsiExpression expression) {
checkTextRange(expression, true);
super.visitExpression(expression);
}
boolean checkTextRange(@NotNull PsiElement expression, boolean expand) {
TextRange range = expression.getTextRange();
if (lineRange.intersects(range)) {
if (expand) {
textRange.set(textRange.get().union(range));
}
return true;
}
return false;
}
public void visitExpressionList(PsiExpressionList expressionList) {
PsiMethod psiMethod = myContextStack.peekFirst();
if (psiMethod != null) {
final String methodName = psiMethod.getName();
final PsiExpression[] expressions = expressionList.getExpressions();
final PsiParameter[] parameters = psiMethod.getParameterList().getParameters();
for (int idx = 0; idx < expressions.length; idx++) {
final String paramName = (idx < parameters.length && !parameters[idx].isVarArgs()) ? parameters[idx].getName() : "arg" + (idx + 1);
myParamNameStack.push(methodName + ": " + paramName + ".");
final PsiExpression argExpression = expressions[idx];
try {
argExpression.accept(this);
} finally {
myParamNameStack.pop();
}
}
} else {
super.visitExpressionList(expressionList);
}
}
@Override
public void visitCallExpression(final PsiCallExpression expression) {
final PsiMethod psiMethod = expression.resolveMethod();
if (psiMethod != null) {
myContextStack.push(psiMethod);
targets.add(new MethodSmartStepTarget(psiMethod, null, expression instanceof PsiMethodCallExpression ? ((PsiMethodCallExpression) expression).getMethodExpression().getReferenceNameElement() : expression instanceof PsiNewExpression ? ((PsiNewExpression) expression).getClassOrAnonymousClassReference() : expression, myInsideLambda, null));
}
try {
super.visitCallExpression(expression);
} finally {
if (psiMethod != null) {
myContextStack.pop();
}
}
}
};
element.accept(methodCollector);
for (PsiElement sibling = element.getNextSibling(); sibling != null; sibling = sibling.getNextSibling()) {
if (!lineRange.intersects(sibling.getTextRange())) {
break;
}
sibling.accept(methodCollector);
}
Range<Integer> lines = new Range<>(doc.getLineNumber(textRange.get().getStartOffset()), doc.getLineNumber(textRange.get().getEndOffset()));
targets.forEach(t -> t.setCallingExpressionLines(lines));
if (!targets.isEmpty()) {
StackFrameProxyImpl frameProxy = suspendContext != null ? suspendContext.getFrameProxy() : null;
if (frameProxy != null) {
try {
Location location = frameProxy.location();
MethodBytecodeUtil.visit(location.method(), location.codeIndex(), new MethodVisitor(Opcodes.API_VERSION) {
boolean myLineMatch = false;
@Override
public void visitLineNumber(int line, Label start) {
myLineMatch = lines.isWithin(line - 1);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
if (myLineMatch) {
targets.removeIf(t -> {
if (t instanceof MethodSmartStepTarget) {
return DebuggerUtilsEx.methodMatches(((MethodSmartStepTarget) t).getMethod(), owner.replace("/", "."), name, desc, suspendContext.getDebugProcess());
}
return false;
});
}
}
}, true);
} catch (Exception e) {
LOG.info(e);
}
}
return targets;
}
}
return Collections.emptyList();
}
use of org.jetbrains.org.objectweb.asm.MethodVisitor in project kotlin by JetBrains.
the class GenerateNotNullAssertionsTest method assertNoIntrinsicsMethodIsCalled.
private void assertNoIntrinsicsMethodIsCalled(String className, boolean noClassFileIsAnError) {
OutputFileCollection classes = generateClassesInFile();
OutputFile file = classes.get(className + ".class");
if (noClassFileIsAnError) {
assertNotNull("File for " + className + " is absent", file);
} else if (file == null) {
return;
}
ClassReader reader = new ClassReader(file.asByteArray());
reader.accept(new ClassVisitor(Opcodes.ASM5) {
@Override
public MethodVisitor visitMethod(int access, @NotNull final String callerName, @NotNull final String callerDesc, String signature, String[] exceptions) {
return new MethodVisitor(Opcodes.ASM5) {
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
assertFalse("Intrinsics method is called: " + name + desc + " Caller: " + callerName + callerDesc, "kotlin/jvm/internal/Intrinsics".equals(owner));
}
};
}
}, 0);
}
Aggregations