Minor. Extract TransformationMethodVisitor with abstract performTransformations(@NotNull MethodNode methodNode)
This commit is contained in:
@@ -541,8 +541,8 @@ public class FunctionCodegen {
|
|||||||
private static String renderByteCodeIfAvailable(MethodVisitor mv) {
|
private static String renderByteCodeIfAvailable(MethodVisitor mv) {
|
||||||
String bytecode = null;
|
String bytecode = null;
|
||||||
|
|
||||||
if (mv instanceof OptimizationMethodVisitor) {
|
if (mv instanceof TransformationMethodVisitor) {
|
||||||
mv = ((OptimizationMethodVisitor) mv).getTraceMethodVisitorIfPossible();
|
mv = ((TransformationMethodVisitor) mv).getTraceMethodVisitorIfPossible();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mv instanceof TraceMethodVisitor) {
|
if (mv instanceof TraceMethodVisitor) {
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.codegen;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
|
||||||
|
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||||
|
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.LocalVariableNode;
|
||||||
|
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.List;
|
||||||
|
|
||||||
|
public abstract class TransformationMethodVisitor extends MethodVisitor {
|
||||||
|
|
||||||
|
private final MethodNode methodNode;
|
||||||
|
private final MethodVisitor delegate;
|
||||||
|
|
||||||
|
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<LocalVariableNode>(5);
|
||||||
|
this.mv = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void 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();
|
||||||
|
|
||||||
|
if (shouldBeTransformed(methodNode)) {
|
||||||
|
performTransformations(methodNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
methodNode.accept(new EndIgnoringMethodVisitorDecorator(Opcodes.ASM5, delegate));
|
||||||
|
|
||||||
|
|
||||||
|
// In case of empty instructions list MethodNode.accept doesn't call visitLocalVariables of delegate
|
||||||
|
// So we just do it here
|
||||||
|
if (methodNode.instructions.size() == 0) {
|
||||||
|
List<LocalVariableNode> localVariables = methodNode.localVariables;
|
||||||
|
// visits local variables
|
||||||
|
int n = localVariables == null ? 0 : localVariables.size();
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
localVariables.get(i).accept(delegate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate.visitEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void performTransformations(@NotNull MethodNode methodNode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You can use it when you need to ignore visit end
|
||||||
|
*/
|
||||||
|
private static class EndIgnoringMethodVisitorDecorator extends MethodVisitor {
|
||||||
|
public EndIgnoringMethodVisitorDecorator(int api, @NotNull MethodVisitor mv) {
|
||||||
|
super(api, mv);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitEnd() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public TraceMethodVisitor getTraceMethodVisitorIfPossible() {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
-78
@@ -18,23 +18,16 @@ package org.jetbrains.kotlin.codegen.optimization;
|
|||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
|
import org.jetbrains.kotlin.codegen.TransformationMethodVisitor;
|
||||||
import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantBoxingMethodTransformer;
|
import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantBoxingMethodTransformer;
|
||||||
import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantCoercionToUnitTransformer;
|
import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantCoercionToUnitTransformer;
|
||||||
import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantNullCheckMethodTransformer;
|
import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantNullCheckMethodTransformer;
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.UtilKt;
|
import org.jetbrains.kotlin.codegen.optimization.common.UtilKt;
|
||||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer;
|
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer;
|
||||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.LocalVariableNode;
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
|
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;
|
public class OptimizationMethodVisitor extends TransformationMethodVisitor {
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class OptimizationMethodVisitor extends MethodVisitor {
|
|
||||||
private static final int MEMORY_LIMIT_BY_METHOD_MB = 50;
|
private static final int MEMORY_LIMIT_BY_METHOD_MB = 50;
|
||||||
|
|
||||||
private static final MethodTransformer MANDATORY_METHOD_TRANSFORMER = new MandatoryMethodTransformer();
|
private static final MethodTransformer MANDATORY_METHOD_TRANSFORMER = new MandatoryMethodTransformer();
|
||||||
@@ -47,8 +40,6 @@ public class OptimizationMethodVisitor extends MethodVisitor {
|
|||||||
new RedundantCoercionToUnitTransformer()
|
new RedundantCoercionToUnitTransformer()
|
||||||
};
|
};
|
||||||
|
|
||||||
private final MethodNode methodNode;
|
|
||||||
private final MethodVisitor delegate;
|
|
||||||
private final boolean disableOptimization;
|
private final boolean disableOptimization;
|
||||||
|
|
||||||
public OptimizationMethodVisitor(
|
public OptimizationMethodVisitor(
|
||||||
@@ -60,79 +51,19 @@ public class OptimizationMethodVisitor extends MethodVisitor {
|
|||||||
@Nullable String signature,
|
@Nullable String signature,
|
||||||
@Nullable String[] exceptions
|
@Nullable String[] exceptions
|
||||||
) {
|
) {
|
||||||
super(Opcodes.ASM5);
|
super(delegate, access, name, desc, signature, exceptions);
|
||||||
this.delegate = delegate;
|
|
||||||
this.methodNode = new MethodNode(access, name, desc, signature, exceptions);
|
|
||||||
this.methodNode.localVariables = new ArrayList<LocalVariableNode>(5);
|
|
||||||
this.mv = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode);
|
|
||||||
this.disableOptimization = disableOptimization;
|
this.disableOptimization = disableOptimization;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitEnd() {
|
protected void performTransformations(@NotNull MethodNode methodNode) {
|
||||||
// force mv to calculate maxStack/maxLocals in case it didn't yet done
|
MANDATORY_METHOD_TRANSFORMER.transform("fake", methodNode);
|
||||||
if (methodNode.maxLocals <= 0 || methodNode.maxStack <= 0) {
|
if (canBeOptimized(methodNode) && !disableOptimization) {
|
||||||
mv.visitMaxs(-1, -1);
|
for (MethodTransformer transformer : OPTIMIZATION_TRANSFORMERS) {
|
||||||
}
|
transformer.transform("fake", methodNode);
|
||||||
|
|
||||||
super.visitEnd();
|
|
||||||
|
|
||||||
if (shouldBeTransformed(methodNode)) {
|
|
||||||
MANDATORY_METHOD_TRANSFORMER.transform("fake", methodNode);
|
|
||||||
if (canBeOptimized(methodNode) && !disableOptimization) {
|
|
||||||
for (MethodTransformer transformer : OPTIMIZATION_TRANSFORMERS) {
|
|
||||||
transformer.transform("fake", methodNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UtilKt.prepareForEmitting(methodNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
methodNode.accept(new EndIgnoringMethodVisitorDecorator(Opcodes.ASM5, delegate));
|
|
||||||
|
|
||||||
|
|
||||||
// In case of empty instructions list MethodNode.accept doesn't call visitLocalVariables of delegate
|
|
||||||
// So we just do it here
|
|
||||||
if (methodNode.instructions.size() == 0) {
|
|
||||||
List<LocalVariableNode> localVariables = methodNode.localVariables;
|
|
||||||
// visits local variables
|
|
||||||
int n = localVariables == null ? 0 : localVariables.size();
|
|
||||||
for (int i = 0; i < n; ++i) {
|
|
||||||
localVariables.get(i).accept(delegate);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UtilKt.prepareForEmitting(methodNode);
|
||||||
delegate.visitEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* You can use it when you need to ignore visit end
|
|
||||||
*/
|
|
||||||
private static class EndIgnoringMethodVisitorDecorator extends MethodVisitor {
|
|
||||||
public EndIgnoringMethodVisitorDecorator(int api, @NotNull MethodVisitor mv) {
|
|
||||||
super(api, mv);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitEnd() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public TraceMethodVisitor getTraceMethodVisitorIfPossible() {
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean canBeOptimized(@NotNull MethodNode node) {
|
private static boolean canBeOptimized(@NotNull MethodNode node) {
|
||||||
|
|||||||
Reference in New Issue
Block a user