Merge pull request #506 from bintree/max-stack-calc-refining
Refining calculation of max stack size. #KT-5548 Fixed
This commit is contained in:
@@ -257,8 +257,8 @@ public class InlineCodegenUtil {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static MaxCalcNode wrapWithMaxLocalCalc(@NotNull MethodNode methodNode) {
|
||||
return new MaxCalcNode(methodNode);
|
||||
public static MethodVisitor wrapWithMaxLocalCalc(@NotNull MethodNode methodNode) {
|
||||
return new MaxStackFrameSizeAndLocalsCalculator(API, methodNode.access, methodNode.desc, methodNode);
|
||||
}
|
||||
|
||||
private static boolean isInteger(@NotNull String string) {
|
||||
|
||||
+6
-5
@@ -24,9 +24,7 @@ import com.intellij.util.containers.Stack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.codegen.AsmUtil;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
import org.jetbrains.org.objectweb.asm.tree.*;
|
||||
|
||||
import java.util.*;
|
||||
@@ -79,9 +77,12 @@ public class InternalFinallyBlockInliner {
|
||||
//sortTryCatchBlocks();/*TODO maybe remove*/
|
||||
mapLabelsToTryCatchBlocks();
|
||||
|
||||
MaxCalcNode tempCalcNode = new MaxCalcNode(inlineFun.desc, (inlineFun.access & Opcodes.ACC_STATIC) != 0);
|
||||
MaxLocalsCalculator tempCalcNode = new MaxLocalsCalculator(
|
||||
InlineCodegenUtil.API,
|
||||
inlineFun.access, inlineFun.desc, null
|
||||
);
|
||||
inlineFun.accept(tempCalcNode);
|
||||
return tempCalcNode.getMaxLocal();
|
||||
return tempCalcNode.getMaxLocals();
|
||||
}
|
||||
|
||||
private void processInlineFunFinallyBlocks() {
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.jet.codegen.inline;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
||||
public class MaxCalcNode extends MethodVisitor {
|
||||
|
||||
private int maxLocal;
|
||||
|
||||
private final MethodNode node;
|
||||
|
||||
public MaxCalcNode(@NotNull MethodNode node) {
|
||||
this(node.desc, node, (node.access & Opcodes.ACC_STATIC) != 0);
|
||||
}
|
||||
|
||||
public MaxCalcNode(@NotNull String desc, boolean isStatic) {
|
||||
this(desc, null, isStatic);
|
||||
}
|
||||
|
||||
private MaxCalcNode(@NotNull String desc, @Nullable MethodNode node, boolean isStatic) {
|
||||
super(InlineCodegenUtil.API, node);
|
||||
this.node = node;
|
||||
maxLocal = (Type.getArgumentsAndReturnSizes(desc) >> 2) - (isStatic ? 1 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(int opcode, int var) {
|
||||
super.visitVarInsn(opcode, var);
|
||||
int size = opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE ? 2 : 1;
|
||||
updateMaxLocal(var, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIincInsn(int var, int increment) {
|
||||
super.visitIincInsn(var, increment);
|
||||
updateMaxLocal(var, 1);
|
||||
}
|
||||
|
||||
private void updateMaxLocal(int index, int size) {
|
||||
maxLocal = Math.max(maxLocal, index + size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMaxs(int maxStack, int maxLocals) {
|
||||
//NB: it's hack for fast maxStack calculation cause it performed only in MethodWriter
|
||||
//temporary solution: maxStack = instruction size (without labels and line numbers) * 2 (cause 1 instruction could put value of size 2)
|
||||
if (node != null) {
|
||||
int size = 0;
|
||||
ListIterator<AbstractInsnNode> iterator = node.instructions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
AbstractInsnNode next = iterator.next();
|
||||
int type = next.getType();
|
||||
if (type != AbstractInsnNode.LINE && type != AbstractInsnNode.LABEL) {
|
||||
size++;
|
||||
}
|
||||
}
|
||||
super.visitMaxs(Math.max(size * 2, maxStack), Math.max(maxLocals, this.maxLocal));
|
||||
}
|
||||
else {
|
||||
super.visitMaxs(maxStack, maxLocals);
|
||||
}
|
||||
}
|
||||
|
||||
public int getMaxLocal() {
|
||||
return maxLocal;
|
||||
}
|
||||
}
|
||||
+10
-3
@@ -33,7 +33,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class OptimizationMethodVisitor extends MethodVisitor {
|
||||
private static final int MAX_INSTRUCTIONS_SIZE_TO_OPTIMIZE = 5000;
|
||||
private static final int MEMORY_LIMIT_BY_METHOD_MB = 50;
|
||||
private static final MethodTransformer MAIN_METHOD_TRANSFORMER = new RedundantNullCheckMethodTransformer(
|
||||
new RedundantBoxingMethodTransformer(null)
|
||||
);
|
||||
@@ -65,8 +65,7 @@ public class OptimizationMethodVisitor extends MethodVisitor {
|
||||
|
||||
super.visitEnd();
|
||||
|
||||
if (methodNode.instructions.size() > 0 &&
|
||||
methodNode.instructions.size() <= MAX_INSTRUCTIONS_SIZE_TO_OPTIMIZE) {
|
||||
if (canBeAnalyzed(methodNode)) {
|
||||
MAIN_METHOD_TRANSFORMER.transform("fake", methodNode);
|
||||
}
|
||||
|
||||
@@ -113,4 +112,12 @@ public class OptimizationMethodVisitor extends MethodVisitor {
|
||||
|
||||
return traceMethodVisitor;
|
||||
}
|
||||
|
||||
private static boolean canBeAnalyzed(@NotNull MethodNode node) {
|
||||
int totalFramesSizeMb = node.instructions.size() *
|
||||
(node.maxLocals + node.maxStack) / (1024 * 1024);
|
||||
|
||||
return node.instructions.size() > 0 &&
|
||||
totalFramesSizeMb < MEMORY_LIMIT_BY_METHOD_MB;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.org.objectweb.asm;
|
||||
|
||||
public class MaxLocalsCalculator extends MethodVisitor {
|
||||
|
||||
private int maxLocals;
|
||||
|
||||
public MaxLocalsCalculator(int api, int access, String descriptor, MethodVisitor mv) {
|
||||
super(api, mv);
|
||||
|
||||
// updates maxLocals
|
||||
int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
|
||||
if ((access & Opcodes.ACC_STATIC) != 0) {
|
||||
--size;
|
||||
}
|
||||
|
||||
maxLocals = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(int opcode, int var) {
|
||||
int n;
|
||||
if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD ||
|
||||
opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) {
|
||||
n = var + 2;
|
||||
} else {
|
||||
n = var + 1;
|
||||
}
|
||||
updateMaxLocals(n);
|
||||
|
||||
super.visitVarInsn(opcode, var);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIincInsn(int var, int increment) {
|
||||
updateMaxLocals(var + 1);
|
||||
|
||||
super.visitIincInsn(var, increment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(
|
||||
String name, String desc,
|
||||
String signature, Label start, Label end,
|
||||
int index
|
||||
) {
|
||||
// updates max locals
|
||||
char c = desc.charAt(0);
|
||||
int n = index + (c == 'J' || c == 'D' ? 2 : 1);
|
||||
updateMaxLocals(n);
|
||||
|
||||
super.visitLocalVariable(name, desc, signature, start, end, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMaxs(int maxStack, int maxLocals) {
|
||||
super.visitMaxs(maxStack, this.maxLocals);
|
||||
}
|
||||
|
||||
public int getMaxLocals() {
|
||||
return maxLocals;
|
||||
}
|
||||
|
||||
private void updateMaxLocals(int nextFreeSlotNumber) {
|
||||
if (nextFreeSlotNumber > maxLocals) {
|
||||
maxLocals = nextFreeSlotNumber;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+422
@@ -0,0 +1,422 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.org.objectweb.asm;
|
||||
|
||||
import com.intellij.openapi.util.Factory;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class MaxStackFrameSizeAndLocalsCalculator extends MaxLocalsCalculator {
|
||||
private final LabelWrapper firstLabel;
|
||||
|
||||
private LabelWrapper currentBlock;
|
||||
private LabelWrapper previousBlock;
|
||||
|
||||
/**
|
||||
* The (relative) stack size after the last visited instruction. This size
|
||||
* is relative to the beginning of the current basic block, i.e., the true
|
||||
* stack size after the last visited instruction is equal to the
|
||||
* {@link MaxStackFrameSizeAndLocalsCalculator.LabelWrapper#inputStackSize} of the current basic block
|
||||
* plus <tt>stackSize</tt>.
|
||||
*/
|
||||
private int stackSize;
|
||||
|
||||
/**
|
||||
* The (relative) maximum stack size after the last visited instruction.
|
||||
* This size is relative to the beginning of the current basic block, i.e.,
|
||||
* the true maximum stack size after the last visited instruction is equal
|
||||
* to the {@link MaxStackFrameSizeAndLocalsCalculator.LabelWrapper#inputStackSize} of the current basic
|
||||
* block plus <tt>stackSize</tt>.
|
||||
*/
|
||||
private int maxStackSize;
|
||||
|
||||
/**
|
||||
* Maximum stack size of this method.
|
||||
*/
|
||||
private int maxStack;
|
||||
|
||||
|
||||
private Collection<ExceptionHandler> exceptionHandlers = new LinkedList<ExceptionHandler>();
|
||||
private Map<Label, LabelWrapper> labelWrappersMap = new HashMap<Label, LabelWrapper>();
|
||||
|
||||
public MaxStackFrameSizeAndLocalsCalculator(int api, int access, String descriptor, MethodVisitor mv) {
|
||||
super(api, access, descriptor, mv);
|
||||
|
||||
firstLabel = getLabelWrapper(new Label());
|
||||
processLabel(firstLabel.label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFrame(int type, int nLocal,
|
||||
Object[] local, int nStack, Object[] stack) {
|
||||
throw new AssertionError("We don't support visitFrame because currently nobody needs");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInsn(int opcode) {
|
||||
increaseStackSize(Frame.SIZE[opcode]);
|
||||
|
||||
// if opcode == ATHROW or xRETURN, ends current block (no successor)
|
||||
if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) {
|
||||
noSuccessor();
|
||||
}
|
||||
|
||||
super.visitInsn(opcode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIntInsn(int opcode, int operand) {
|
||||
if (opcode != Opcodes.NEWARRAY) {
|
||||
// updates current and max stack sizes only if it's not NEWARRAY
|
||||
// (stack size variation is 0 for NEWARRAY and +1 BIPUSH or SIPUSH)
|
||||
increaseStackSize(1);
|
||||
}
|
||||
|
||||
super.visitIntInsn(opcode, operand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(int opcode, int var) {
|
||||
increaseStackSize(Frame.SIZE[opcode]);
|
||||
|
||||
super.visitVarInsn(opcode, var);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeInsn(int opcode, String type) {
|
||||
if (opcode == Opcodes.NEW) {
|
||||
// updates current and max stack sizes only if opcode == NEW
|
||||
// (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF)
|
||||
increaseStackSize(1);
|
||||
}
|
||||
|
||||
super.visitTypeInsn(opcode, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(int opcode, String owner,
|
||||
String name, String desc) {
|
||||
int stackSizeVariation;
|
||||
|
||||
// computes the stack size variation
|
||||
char c = desc.charAt(0);
|
||||
switch (opcode) {
|
||||
case Opcodes.GETSTATIC:
|
||||
stackSizeVariation = c == 'D' || c == 'J' ? 2 : 1;
|
||||
break;
|
||||
case Opcodes.PUTSTATIC:
|
||||
stackSizeVariation = c == 'D' || c == 'J' ? -2 : -1;
|
||||
break;
|
||||
case Opcodes.GETFIELD:
|
||||
stackSizeVariation = c == 'D' || c == 'J' ? 1 : 0;
|
||||
break;
|
||||
// case Constants.PUTFIELD:
|
||||
default:
|
||||
stackSizeVariation = c == 'D' || c == 'J' ? -3 : -2;
|
||||
break;
|
||||
}
|
||||
|
||||
increaseStackSize(stackSizeVariation);
|
||||
|
||||
super.visitFieldInsn(opcode, owner, name, desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
int opcode, String owner,
|
||||
String name, String desc, boolean itf
|
||||
) {
|
||||
int argSize = Type.getArgumentsAndReturnSizes(desc);
|
||||
int sizeVariation;
|
||||
if (opcode == Opcodes.INVOKESTATIC) {
|
||||
sizeVariation = (argSize & 0x03) - (argSize >> 2) + 1;
|
||||
} else {
|
||||
sizeVariation = (argSize & 0x03) - (argSize >> 2);
|
||||
}
|
||||
|
||||
increaseStackSize(sizeVariation);
|
||||
|
||||
super.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(
|
||||
String name, String desc,
|
||||
Handle bsm, Object... bsmArgs
|
||||
) {
|
||||
int argSize = Type.getArgumentsAndReturnSizes(desc);
|
||||
increaseStackSize((argSize & 0x03) - (argSize >> 2) + 1);
|
||||
|
||||
super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJumpInsn(
|
||||
int opcode, Label label
|
||||
) {
|
||||
if (currentBlock != null) {
|
||||
// updates current stack size (max stack size unchanged
|
||||
// because stack size variation always negative in this
|
||||
// case)
|
||||
stackSize += Frame.SIZE[opcode];
|
||||
addSuccessor(getLabelWrapper(label), stackSize);
|
||||
|
||||
if (opcode == Opcodes.GOTO) {
|
||||
noSuccessor();
|
||||
}
|
||||
}
|
||||
|
||||
super.visitJumpInsn(opcode, label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLabel(Label label) {
|
||||
processLabel(label);
|
||||
super.visitLabel(label);
|
||||
}
|
||||
|
||||
private void processLabel(Label label) {
|
||||
LabelWrapper wrapper = getLabelWrapper(label);
|
||||
|
||||
if (currentBlock != null) {
|
||||
// ends current block (with one new successor)
|
||||
currentBlock.outputStackMax = maxStackSize;
|
||||
addSuccessor(wrapper, stackSize);
|
||||
}
|
||||
|
||||
// begins a new current block
|
||||
currentBlock = wrapper;
|
||||
// resets the relative current and max stack sizes
|
||||
stackSize = 0;
|
||||
maxStackSize = 0;
|
||||
|
||||
if (previousBlock != null) {
|
||||
previousBlock.nextLabel = wrapper;
|
||||
}
|
||||
|
||||
previousBlock = wrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(Object cst) {
|
||||
// computes the stack size variation
|
||||
if (cst instanceof Long || cst instanceof Double) {
|
||||
increaseStackSize(2);
|
||||
} else {
|
||||
increaseStackSize(1);
|
||||
}
|
||||
|
||||
super.visitLdcInsn(cst);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableSwitchInsn(int min, int max,
|
||||
Label dflt, Label... labels) {
|
||||
visitSwitchInsn(dflt, labels);
|
||||
|
||||
super.visitTableSwitchInsn(min, max, dflt, labels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLookupSwitchInsn(Label dflt, int[] keys,
|
||||
Label[] labels) {
|
||||
visitSwitchInsn(dflt, labels);
|
||||
|
||||
super.visitLookupSwitchInsn(dflt, keys, labels);
|
||||
}
|
||||
|
||||
private void visitSwitchInsn(Label dflt, Label[] labels) {
|
||||
if (currentBlock != null) {
|
||||
// updates current stack size (max stack size unchanged)
|
||||
--stackSize;
|
||||
// adds current block successors
|
||||
addSuccessor(getLabelWrapper(dflt), stackSize);
|
||||
for (int i = 0; i < labels.length; ++i) {
|
||||
addSuccessor(getLabelWrapper(labels[i]), stackSize);
|
||||
}
|
||||
// ends current block
|
||||
noSuccessor();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMultiANewArrayInsn(String desc, int dims) {
|
||||
if (currentBlock != null) {
|
||||
increaseStackSize(dims - 1);
|
||||
}
|
||||
|
||||
super.visitMultiANewArrayInsn(desc, dims);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMaxs(int maxStack, int maxLocals) {
|
||||
// completes the control flow graph with exception handler blocks
|
||||
for (ExceptionHandler handler : exceptionHandlers) {
|
||||
LabelWrapper l = handler.start;
|
||||
LabelWrapper e = handler.end;
|
||||
|
||||
while (l != e) {
|
||||
l.addSuccessor(handler.handlerLabel, 0, true);
|
||||
l = l.nextLabel;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* control flow analysis algorithm: while the block stack is not
|
||||
* empty, pop a block from this stack, update the max stack size,
|
||||
* compute the true (non relative) begin stack size of the
|
||||
* successors of this block, and push these successors onto the
|
||||
* stack (unless they have already been pushed onto the stack).
|
||||
* Note: by hypothesis, the {@link LabelWrapper#inputStackSize} of the
|
||||
* blocks in the block stack are the true (non relative) beginning
|
||||
* stack sizes of these blocks.
|
||||
*/
|
||||
int max = 0;
|
||||
Stack<LabelWrapper> stack = new Stack<LabelWrapper>();
|
||||
Set<LabelWrapper> pushed = new HashSet<LabelWrapper>();
|
||||
|
||||
stack.push(firstLabel);
|
||||
pushed.add(firstLabel);
|
||||
|
||||
while (!stack.empty()) {
|
||||
LabelWrapper current = stack.pop();
|
||||
int start = current.inputStackSize;
|
||||
int blockMax = start + current.outputStackMax;
|
||||
|
||||
// updates the global max stack size
|
||||
if (blockMax > max) {
|
||||
max = blockMax;
|
||||
}
|
||||
|
||||
// analyzes the successors of the block
|
||||
for (ControlFlowEdge edge : current.successors) {
|
||||
LabelWrapper successor = edge.successor;
|
||||
|
||||
if (!pushed.contains(successor)) {
|
||||
// computes its true beginning stack size...
|
||||
successor.inputStackSize = edge.isExceptional ? 1 : start + edge.outputStackSize;
|
||||
// ...and pushes it onto the stack
|
||||
pushed.add(successor);
|
||||
stack.push(successor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.maxStack = Math.max(this.maxStack, Math.max(maxStack, max));
|
||||
|
||||
super.visitMaxs(this.maxStack, maxLocals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTryCatchBlock(
|
||||
Label start, Label end,
|
||||
Label handler, String type
|
||||
) {
|
||||
ExceptionHandler exceptionHandler = new ExceptionHandler(
|
||||
getLabelWrapper(start), getLabelWrapper(end), getLabelWrapper(handler)
|
||||
);
|
||||
|
||||
exceptionHandlers.add(exceptionHandler);
|
||||
|
||||
super.visitTryCatchBlock(start, end, handler, type);
|
||||
}
|
||||
|
||||
private static class ExceptionHandler {
|
||||
private final LabelWrapper start;
|
||||
private final LabelWrapper end;
|
||||
private final LabelWrapper handlerLabel;
|
||||
|
||||
public ExceptionHandler(
|
||||
LabelWrapper start,
|
||||
LabelWrapper end,
|
||||
LabelWrapper handlerLabel
|
||||
) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.handlerLabel = handlerLabel;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ControlFlowEdge {
|
||||
private final LabelWrapper successor;
|
||||
private final int outputStackSize;
|
||||
private final boolean isExceptional;
|
||||
|
||||
public ControlFlowEdge(LabelWrapper successor, int outputStackSize, boolean isExceptional) {
|
||||
this.successor = successor;
|
||||
this.outputStackSize = outputStackSize;
|
||||
this.isExceptional = isExceptional;
|
||||
}
|
||||
}
|
||||
|
||||
private static class LabelWrapper {
|
||||
private final Label label;
|
||||
private LabelWrapper nextLabel = null;
|
||||
private final Collection<ControlFlowEdge> successors = new LinkedList<ControlFlowEdge>();
|
||||
|
||||
private int outputStackMax = 0;
|
||||
private int inputStackSize = 0;
|
||||
public LabelWrapper(Label label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
private void addSuccessor(LabelWrapper successor, int outputStackSize, boolean isExceptional) {
|
||||
successors.add(new ControlFlowEdge(successor, outputStackSize, isExceptional));
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Utility methods
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
private LabelWrapper getLabelWrapper(final Label label) {
|
||||
return ContainerUtil.getOrCreate(labelWrappersMap, label, new Factory<LabelWrapper>() {
|
||||
@Override
|
||||
public LabelWrapper create() {
|
||||
return new LabelWrapper(label);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void increaseStackSize(int variation) {
|
||||
updateStackSize(stackSize + variation);
|
||||
}
|
||||
|
||||
private void updateStackSize(int size) {
|
||||
if (size > maxStackSize) {
|
||||
maxStackSize = size;
|
||||
}
|
||||
|
||||
stackSize = size;
|
||||
}
|
||||
|
||||
private void addSuccessor(LabelWrapper successor, int outputStackSize) {
|
||||
currentBlock.addSuccessor(successor, outputStackSize, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the current basic block. This method must be used in the case where
|
||||
* the current basic block does not have any successor.
|
||||
*/
|
||||
private void noSuccessor() {
|
||||
if (currentBlock != null) {
|
||||
currentBlock.outputStackMax = maxStackSize;
|
||||
currentBlock = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user