|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package jdk.jfr.internal.instrument; |
|
|
|
import java.util.ArrayList; |
|
import java.util.List; |
|
|
|
import jdk.internal.org.objectweb.asm.Label; |
|
import jdk.internal.org.objectweb.asm.MethodVisitor; |
|
import jdk.internal.org.objectweb.asm.Opcodes; |
|
import jdk.internal.org.objectweb.asm.commons.LocalVariablesSorter; |
|
import jdk.internal.org.objectweb.asm.commons.Remapper; |
|
import jdk.internal.org.objectweb.asm.commons.SimpleRemapper; |
|
import jdk.internal.org.objectweb.asm.tree.MethodNode; |
|
import jdk.jfr.internal.LogLevel; |
|
import jdk.jfr.internal.LogTag; |
|
import jdk.jfr.internal.Logger; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Deprecated |
|
final class JIMethodCallInliner extends LocalVariablesSorter { |
|
|
|
private final String oldClass; |
|
private final String newClass; |
|
private final MethodNode inlineTarget; |
|
private final List<CatchBlock> blocks = new ArrayList<>(); |
|
private boolean inlining; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public JIMethodCallInliner(int access, String desc, MethodVisitor mv, |
|
MethodNode inlineTarget, String oldClass, String newClass) { |
|
super(Opcodes.ASM5, access, desc, mv); |
|
this.oldClass = oldClass; |
|
this.newClass = newClass; |
|
this.inlineTarget = inlineTarget; |
|
|
|
Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, "MethodCallInliner: targetMethod=" + newClass + "." |
|
+ inlineTarget.name + inlineTarget.desc); |
|
} |
|
|
|
@Override |
|
public void visitMethodInsn(int opcode, String owner, String name, |
|
String desc, boolean itf) { |
|
|
|
if (!shouldBeInlined(owner, name, desc)) { |
|
|
|
mv.visitMethodInsn(opcode, owner, name, desc, itf); |
|
return; |
|
} |
|
// If the call should be inlined, we create a MethodInliningAdapter |
|
// The MIA will walk the instructions in the inlineTarget and add them |
|
|
|
Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, "Inlining call to " + name + desc); |
|
Remapper remapper = new SimpleRemapper(oldClass, newClass); |
|
Label end = new Label(); |
|
inlining = true; |
|
inlineTarget.instructions.resetLabels(); |
|
JIMethodInliningAdapter mia = new JIMethodInliningAdapter(this, end, |
|
opcode == Opcodes.INVOKESTATIC ? Opcodes.ACC_STATIC : 0, desc, |
|
remapper); |
|
inlineTarget.accept(mia); |
|
inlining = false; |
|
super.visitLabel(end); |
|
} |
|
|
|
|
|
|
|
*/ |
|
private boolean shouldBeInlined(String owner, String name, String desc) { |
|
return inlineTarget.desc.equals(desc) && inlineTarget.name.equals(name) |
|
&& owner.equals(newClass.replace('.', '/')); |
|
} |
|
|
|
@Override |
|
public void visitTryCatchBlock(Label start, Label end, Label handler, |
|
String type) { |
|
if (!inlining) { |
|
// try-catch blocks are saved here and replayed at the end |
|
|
|
blocks.add(new CatchBlock(start, end, handler, type)); |
|
} else { |
|
super.visitTryCatchBlock(start, end, handler, type); |
|
} |
|
} |
|
|
|
@Override |
|
public void visitMaxs(int stack, int locals) { |
|
for (CatchBlock b : blocks) { |
|
super.visitTryCatchBlock(b.start, b.end, b.handler, b.type); |
|
} |
|
super.visitMaxs(stack, locals); |
|
} |
|
|
|
static final class CatchBlock { |
|
|
|
final Label start; |
|
final Label end; |
|
final Label handler; |
|
final String type; |
|
|
|
CatchBlock(Label start, Label end, Label handler, String type) { |
|
this.start = start; |
|
this.end = end; |
|
this.handler = handler; |
|
this.type = type; |
|
} |
|
} |
|
} |