aboutsummaryrefslogtreecommitdiff
path: root/exec/java-exec/src/main/java/org/apache/drill/exec/compile/bytecode/MethodAnalyzer.java
diff options
context:
space:
mode:
Diffstat (limited to 'exec/java-exec/src/main/java/org/apache/drill/exec/compile/bytecode/MethodAnalyzer.java')
-rw-r--r--exec/java-exec/src/main/java/org/apache/drill/exec/compile/bytecode/MethodAnalyzer.java138
1 files changed, 110 insertions, 28 deletions
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/compile/bytecode/MethodAnalyzer.java b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/bytecode/MethodAnalyzer.java
index 78cf16fc1..ae900cf71 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/compile/bytecode/MethodAnalyzer.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/bytecode/MethodAnalyzer.java
@@ -17,16 +17,26 @@
*/
package org.apache.drill.exec.compile.bytecode;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.InsnList;
+import org.objectweb.asm.tree.LabelNode;
+import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.analysis.Analyzer;
+import org.objectweb.asm.tree.analysis.AnalyzerException;
import org.objectweb.asm.tree.analysis.Frame;
import org.objectweb.asm.tree.analysis.Interpreter;
import org.objectweb.asm.tree.analysis.Value;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* Analyzer that allows us to inject additional functionality into ASMs basic analysis.
*
* <p>We need to be able to keep track of local variables that are assigned to each other
- * so that we can infer their replacability (for scalar replacement). In order to do that,
+ * so that we can infer their replaceability (for scalar replacement). In order to do that,
* we need to know when local variables are assigned (with the old value being overwritten)
* so that we can associate them with the new value, and hence determine whether they can
* also be replaced, or not.
@@ -36,22 +46,71 @@ import org.objectweb.asm.tree.analysis.Value;
* as factories that will provide our own derivative of Frame<> which we use to detect
*/
public class MethodAnalyzer<V extends Value> extends Analyzer <V> {
+
+ // list of method instructions which is analyzed
+ private InsnList insnList;
+
+ public MethodAnalyzer(Interpreter<V> interpreter) {
+ super(interpreter);
+ }
+
+ @Override
+ protected Frame<V> newFrame(int maxLocals, int maxStack) {
+ return new AssignmentTrackingFrame<>(maxLocals, maxStack);
+ }
+
+ @Override
+ protected Frame<V> newFrame(Frame<? extends V> src) {
+ return new AssignmentTrackingFrame<>(src);
+ }
+
+ @Override
+ protected void newControlFlowEdge(int insnIndex, int successorIndex) {
+ AssignmentTrackingFrame<V> oldFrame = (AssignmentTrackingFrame<V>) getFrames()[insnIndex];
+ AbstractInsnNode insn = insnList.get(insnIndex);
+ if (insn.getType() == AbstractInsnNode.LABEL) {
+ // checks whether current label corresponds to the end of conditional block to restore previous
+ // local variables set
+ if (insn.equals(oldFrame.labelsStack.peekFirst())) {
+ oldFrame.localVariablesSet.pop();
+ oldFrame.labelsStack.pop();
+ }
+ }
+ }
+
+ @Override
+ public Frame<V>[] analyze(String owner, MethodNode method) throws AnalyzerException {
+ insnList = method.instructions;
+ return super.analyze(owner, method);
+ }
+
/**
* Custom Frame<> that captures setLocal() calls in order to associate values
- * that are assigned to the same local variable slot.
+ * that are assigned to the same local variable slot. Also it controls stack to determine whether
+ * object was assigned to the value declared outside of conditional block.
*
* <p>Since this is almost a pass-through, the constructors' arguments match
* those from Frame<>.
*/
private static class AssignmentTrackingFrame<V extends Value> extends Frame<V> {
+
+ // represents stack of variable sets declared inside current code block
+ private final Deque<Set<Integer>> localVariablesSet;
+
+ // stack of LabelNode instances which correspond to the end of conditional block
+ private final Deque<LabelNode> labelsStack;
+
/**
* Constructor.
*
* @param nLocals the number of locals the frame should have
* @param nStack the maximum size of the stack the frame should have
*/
- public AssignmentTrackingFrame(final int nLocals, final int nStack) {
+ public AssignmentTrackingFrame(int nLocals, int nStack) {
super(nLocals, nStack);
+ localVariablesSet = new ArrayDeque<>();
+ localVariablesSet.push(new HashSet<>());
+ labelsStack = new ArrayDeque<>();
}
/**
@@ -59,47 +118,70 @@ public class MethodAnalyzer<V extends Value> extends Analyzer <V> {
*
* @param src the frame being copied
*/
- public AssignmentTrackingFrame(final Frame<? extends V> src) {
+ @SuppressWarnings("unchecked")
+ public AssignmentTrackingFrame(Frame<? extends V> src) {
super(src);
+ AssignmentTrackingFrame trackingFrame = (AssignmentTrackingFrame) src;
+ localVariablesSet = new ArrayDeque<>();
+ for (Set<Integer> integers : (Deque<Set<Integer>>) trackingFrame.localVariablesSet) {
+ localVariablesSet.addFirst(new HashSet<>(integers));
+ }
+ labelsStack = new ArrayDeque<>(trackingFrame.labelsStack);
}
@Override
- public void setLocal(final int i, final V value) {
+ public void setLocal(int i, V value) {
/*
* If we're replacing one ReplacingBasicValue with another, we need to
- * associate them together so that they will have the same replacability
+ * associate them together so that they will have the same replaceability
* attributes. We also track the local slot the new value will be stored in.
*/
if (value instanceof ReplacingBasicValue) {
- final ReplacingBasicValue replacingValue = (ReplacingBasicValue) value;
+ ReplacingBasicValue replacingValue = (ReplacingBasicValue) value;
replacingValue.setFrameSlot(i);
- final V localValue = getLocal(i);
- if ((localValue != null) && (localValue instanceof ReplacingBasicValue)) {
- final ReplacingBasicValue localReplacingValue = (ReplacingBasicValue) localValue;
+ V localValue = getLocal(i);
+ Set<Integer> currentLocalVars = localVariablesSet.element();
+ if (localValue instanceof ReplacingBasicValue) {
+ if (!currentLocalVars.contains(i)) {
+ // value is assigned to object declared outside of conditional block
+ replacingValue.setAssignedInConditionalBlock();
+ }
+ ReplacingBasicValue localReplacingValue = (ReplacingBasicValue) localValue;
localReplacingValue.associate(replacingValue);
+ } else {
+ currentLocalVars.add(i);
}
}
super.setLocal(i, value);
}
- }
- /**
- * Constructor.
- *
- * @param interpreter the interpreter to use
- */
- public MethodAnalyzer(final Interpreter<V> interpreter) {
- super(interpreter);
- }
-
- @Override
- protected Frame<V> newFrame(final int maxLocals, final int maxStack) {
- return new AssignmentTrackingFrame<V>(maxLocals, maxStack);
- }
-
- @Override
- protected Frame<V> newFrame(final Frame<? extends V> src) {
- return new AssignmentTrackingFrame<V>(src);
+ @Override
+ public void initJumpTarget(int opcode, LabelNode target) {
+ if (target != null) {
+ switch (opcode) {
+ case IFEQ:
+ case IFNE:
+ case IFLT:
+ case IFGE:
+ case IFGT:
+ case IFLE:
+ case IF_ICMPEQ:
+ case IF_ICMPNE:
+ case IF_ICMPLT:
+ case IF_ICMPGE:
+ case IF_ICMPGT:
+ case IF_ICMPLE:
+ case IF_ACMPEQ:
+ case IF_ACMPNE:
+ case IFNONNULL:
+ // for the case when conditional block is handled, creates new variables set
+ // to store local variables declared inside current conditional block and
+ // stores its target LabelNode to restore previous variables set after conditional block is ended
+ localVariablesSet.push(new HashSet<>());
+ labelsStack.push(target);
+ }
+ }
+ }
}
}