Convert TransformationMethodVisitor: step 2
This commit is contained in:
@@ -14,111 +14,96 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.codegen;
|
package org.jetbrains.kotlin.codegen
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
import org.jetbrains.org.objectweb.asm.util.Textifier
|
||||||
import org.jetbrains.org.objectweb.asm.tree.LocalVariableNode;
|
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor
|
||||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
|
|
||||||
import org.jetbrains.org.objectweb.asm.util.Textifier;
|
|
||||||
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.getNodeText;
|
import org.jetbrains.kotlin.codegen.inline.nodeText
|
||||||
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.wrapWithMaxLocalCalc;
|
import org.jetbrains.kotlin.codegen.inline.wrapWithMaxLocalCalc
|
||||||
|
|
||||||
public abstract class TransformationMethodVisitor extends MethodVisitor {
|
abstract class TransformationMethodVisitor(
|
||||||
|
private val delegate: MethodVisitor,
|
||||||
|
access: Int,
|
||||||
|
name: String,
|
||||||
|
desc: String,
|
||||||
|
signature: String?,
|
||||||
|
exceptions: Array<String>?
|
||||||
|
) : MethodVisitor(Opcodes.ASM5) {
|
||||||
|
|
||||||
private final MethodNode methodNode;
|
private val methodNode = MethodNode(access, name, desc, signature, exceptions).apply {
|
||||||
private final MethodVisitor delegate;
|
localVariables = ArrayList(5)
|
||||||
|
|
||||||
public TransformationMethodVisitor(
|
|
||||||
@NotNull MethodVisitor delegate,
|
|
||||||
int access,
|
|
||||||
@NotNull String name,
|
|
||||||
@NotNull String desc,
|
|
||||||
@Nullable String signature,
|
|
||||||
@Nullable String[] exceptions
|
|
||||||
) {
|
|
||||||
super(Opcodes.ASM5);
|
|
||||||
this.delegate = delegate;
|
|
||||||
this.methodNode = new MethodNode(access, name, desc, signature, exceptions);
|
|
||||||
this.methodNode.localVariables = new ArrayList<>(5);
|
|
||||||
this.mv = wrapWithMaxLocalCalc(methodNode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
val traceMethodVisitorIfPossible: TraceMethodVisitor?
|
||||||
public void visitEnd() {
|
get() {
|
||||||
// force mv to calculate maxStack/maxLocals in case it didn't yet done
|
val traceMethodVisitor = TraceMethodVisitor(Textifier())
|
||||||
if (methodNode.maxLocals <= 0 || methodNode.maxStack <= 0) {
|
try {
|
||||||
mv.visitMaxs(-1, -1);
|
methodNode.accept(traceMethodVisitor)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return traceMethodVisitor
|
||||||
}
|
}
|
||||||
|
|
||||||
super.visitEnd();
|
init {
|
||||||
|
mv = wrapWithMaxLocalCalc(methodNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitEnd() {
|
||||||
|
// force mv to calculate maxStack/maxLocals in case it didn't yet done
|
||||||
|
if (methodNode.maxLocals <= 0 || methodNode.maxStack <= 0) {
|
||||||
|
mv.visitMaxs(-1, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
super.visitEnd()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (shouldBeTransformed(methodNode)) {
|
if (shouldBeTransformed(methodNode)) {
|
||||||
performTransformations(methodNode);
|
performTransformations(methodNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
methodNode.accept(new EndIgnoringMethodVisitorDecorator(Opcodes.ASM5, delegate));
|
methodNode.accept(EndIgnoringMethodVisitorDecorator(Opcodes.ASM5, delegate))
|
||||||
|
|
||||||
|
|
||||||
// In case of empty instructions list MethodNode.accept doesn't call visitLocalVariables of delegate
|
// In case of empty instructions list MethodNode.accept doesn't call visitLocalVariables of delegate
|
||||||
// So we just do it here
|
// So we just do it here
|
||||||
if (methodNode.instructions.size() == 0
|
if (methodNode.instructions.size() == 0
|
||||||
// MethodNode does not create a list of variables for abstract methods, so we would get NPE in accept() instead
|
// MethodNode does not create a list of variables for abstract methods, so we would get NPE in accept() instead
|
||||||
&& (!(delegate instanceof MethodNode) || methodNode.localVariables != null)
|
&& (delegate !is MethodNode || methodNode.localVariables != null)
|
||||||
) {
|
) {
|
||||||
List<LocalVariableNode> localVariables = methodNode.localVariables;
|
val localVariables = methodNode.localVariables
|
||||||
// visits local variables
|
// visits local variables
|
||||||
int n = localVariables == null ? 0 : localVariables.size();
|
val n = localVariables?.size ?: 0
|
||||||
for (int i = 0; i < n; ++i) {
|
for (i in 0 until n) {
|
||||||
localVariables.get(i).accept(delegate);
|
localVariables!![i].accept(delegate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate.visitEnd();
|
delegate.visitEnd()
|
||||||
}
|
} catch (t: Throwable) {
|
||||||
catch (Throwable t) {
|
throw CompilationException("Couldn't transform method node:\n" + methodNode.nodeText, t, null)
|
||||||
throw new CompilationException("Couldn't transform method node:\n" + getNodeText(methodNode), t, null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void performTransformations(@NotNull MethodNode methodNode);
|
protected abstract fun performTransformations(methodNode: MethodNode)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* You can use it when you need to ignore visit end
|
* You can use it when you need to ignore visit end
|
||||||
*/
|
*/
|
||||||
private static class EndIgnoringMethodVisitorDecorator extends MethodVisitor {
|
private class EndIgnoringMethodVisitorDecorator(api: Int, mv: MethodVisitor) : MethodVisitor(api, mv) {
|
||||||
public EndIgnoringMethodVisitorDecorator(int api, @NotNull MethodVisitor mv) {
|
|
||||||
super(api, mv);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitEnd() {
|
|
||||||
|
|
||||||
|
override fun visitEnd() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private fun shouldBeTransformed(node: MethodNode): Boolean {
|
||||||
public TraceMethodVisitor getTraceMethodVisitorIfPossible() {
|
return node.instructions.size() > 0
|
||||||
TraceMethodVisitor traceMethodVisitor = new TraceMethodVisitor(new Textifier());
|
|
||||||
try {
|
|
||||||
methodNode.accept(traceMethodVisitor);
|
|
||||||
}
|
|
||||||
catch (Throwable e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return traceMethodVisitor;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean shouldBeTransformed(@NotNull MethodNode node) {
|
|
||||||
return node.instructions.size() > 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user