You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by th...@apache.org on 2018/11/29 00:34:04 UTC
[17/46] tapestry-5 git commit: TAP5-2588: upgrading from ASM 6 to 7
for Java 9+ support
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1c71aec7/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Analyzer.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Analyzer.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Analyzer.java
old mode 100644
new mode 100755
index fc88d8e..62de39d
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Analyzer.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Analyzer.java
@@ -1,39 +1,36 @@
-/***
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
+// ASM: a very small and fast Java bytecode manipulation framework
+// Copyright (c) 2000-2011 INRIA, France Telecom
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
package org.apache.tapestry5.internal.plastic.asm.tree.analysis;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-
import org.apache.tapestry5.internal.plastic.asm.Opcodes;
import org.apache.tapestry5.internal.plastic.asm.Type;
import org.apache.tapestry5.internal.plastic.asm.tree.AbstractInsnNode;
@@ -48,503 +45,559 @@ import org.apache.tapestry5.internal.plastic.asm.tree.TryCatchBlockNode;
import org.apache.tapestry5.internal.plastic.asm.tree.VarInsnNode;
/**
- * A semantic bytecode analyzer. <i>This class does not fully check that JSR and
- * RET instructions are valid.</i>
- *
- * @param <V>
- * type of the Value used for the analysis.
- *
+ * A semantic bytecode analyzer. <i>This class does not fully check that JSR and RET instructions
+ * are valid.</i>
+ *
+ * @param <V> type of the Value used for the analysis.
* @author Eric Bruneton
*/
public class Analyzer<V extends Value> implements Opcodes {
- private final Interpreter<V> interpreter;
-
- private int n;
-
- private InsnList insns;
-
- private List<TryCatchBlockNode>[] handlers;
-
- private Frame<V>[] frames;
-
- private Subroutine[] subroutines;
-
- private boolean[] queued;
-
- private int[] queue;
-
- private int top;
+ /** The interpreter to use to symbolically interpret the bytecode instructions. */
+ private final Interpreter<V> interpreter;
+
+ /** The instructions of the currently analyzed method. */
+ private InsnList insnList;
+
+ /** The size of {@link #insnList}. */
+ private int insnListSize;
+
+ /** The exception handlers of the currently analyzed method (one list per instruction index). */
+ private List<TryCatchBlockNode>[] handlers;
+
+ /** The execution stack frames of the currently analyzed method (one per instruction index). */
+ private Frame<V>[] frames;
+
+ /** The subroutines of the currently analyzed method (one per instruction index). */
+ private Subroutine[] subroutines;
+
+ /** The instructions that remain to process (one boolean per instruction index). */
+ private boolean[] inInstructionsToProcess;
+
+ /** The indices of the instructions that remain to process in the currently analyzed method. */
+ private int[] instructionsToProcess;
+
+ /** The number of instructions that remain to process in the currently analyzed method. */
+ private int numInstructionsToProcess;
+
+ /**
+ * Constructs a new {@link Analyzer}.
+ *
+ * @param interpreter the interpreter to use to symbolically interpret the bytecode instructions.
+ */
+ public Analyzer(final Interpreter<V> interpreter) {
+ this.interpreter = interpreter;
+ }
+
+ /**
+ * Analyzes the given method.
+ *
+ * @param owner the internal name of the class to which 'method' belongs.
+ * @param method the method to be analyzed.
+ * @return the symbolic state of the execution stack frame at each bytecode instruction of the
+ * method. The size of the returned array is equal to the number of instructions (and labels)
+ * of the method. A given frame is {@literal null} if and only if the corresponding
+ * instruction cannot be reached (dead code).
+ * @throws AnalyzerException if a problem occurs during the analysis.
+ */
+ @SuppressWarnings("unchecked")
+ public Frame<V>[] analyze(final String owner, final MethodNode method) throws AnalyzerException {
+ if ((method.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) {
+ frames = (Frame<V>[]) new Frame<?>[0];
+ return frames;
+ }
+ insnList = method.instructions;
+ insnListSize = insnList.size();
+ handlers = (List<TryCatchBlockNode>[]) new List<?>[insnListSize];
+ frames = (Frame<V>[]) new Frame<?>[insnListSize];
+ subroutines = new Subroutine[insnListSize];
+ inInstructionsToProcess = new boolean[insnListSize];
+ instructionsToProcess = new int[insnListSize];
+ numInstructionsToProcess = 0;
+
+ // For each exception handler, and each instruction within its range, record in 'handlers' the
+ // fact that execution can flow from this instruction to the exception handler.
+ for (int i = 0; i < method.tryCatchBlocks.size(); ++i) {
+ TryCatchBlockNode tryCatchBlock = method.tryCatchBlocks.get(i);
+ int startIndex = insnList.indexOf(tryCatchBlock.start);
+ int endIndex = insnList.indexOf(tryCatchBlock.end);
+ for (int j = startIndex; j < endIndex; ++j) {
+ List<TryCatchBlockNode> insnHandlers = handlers[j];
+ if (insnHandlers == null) {
+ insnHandlers = new ArrayList<TryCatchBlockNode>();
+ handlers[j] = insnHandlers;
+ }
+ insnHandlers.add(tryCatchBlock);
+ }
+ }
- /**
- * Constructs a new {@link Analyzer}.
- *
- * @param interpreter
- * the interpreter to be used to symbolically interpret the
- * bytecode instructions.
- */
- public Analyzer(final Interpreter<V> interpreter) {
- this.interpreter = interpreter;
+ // For each instruction, compute the subroutine to which it belongs.
+ // Follow the main 'subroutine', and collect the jsr instructions to nested subroutines.
+ Subroutine main = new Subroutine(null, method.maxLocals, null);
+ List<AbstractInsnNode> jsrInsns = new ArrayList<AbstractInsnNode>();
+ findSubroutine(0, main, jsrInsns);
+ // Follow the nested subroutines, and collect their own nested subroutines, until all
+ // subroutines are found.
+ Map<LabelNode, Subroutine> jsrSubroutines = new HashMap<LabelNode, Subroutine>();
+ while (!jsrInsns.isEmpty()) {
+ JumpInsnNode jsrInsn = (JumpInsnNode) jsrInsns.remove(0);
+ Subroutine subroutine = jsrSubroutines.get(jsrInsn.label);
+ if (subroutine == null) {
+ subroutine = new Subroutine(jsrInsn.label, method.maxLocals, jsrInsn);
+ jsrSubroutines.put(jsrInsn.label, subroutine);
+ findSubroutine(insnList.indexOf(jsrInsn.label), subroutine, jsrInsns);
+ } else {
+ subroutine.callers.add(jsrInsn);
+ }
+ }
+ // Clear the main 'subroutine', which is not a real subroutine (and was used only as an
+ // intermediate step above to find the real ones).
+ for (int i = 0; i < insnListSize; ++i) {
+ if (subroutines[i] != null && subroutines[i].start == null) {
+ subroutines[i] = null;
+ }
}
- /**
- * Analyzes the given method.
- *
- * @param owner
- * the internal name of the class to which the method belongs.
- * @param m
- * the method to be analyzed.
- * @return the symbolic state of the execution stack frame at each bytecode
- * instruction of the method. The size of the returned array is
- * equal to the number of instructions (and labels) of the method. A
- * given frame is <tt>null</tt> if and only if the corresponding
- * instruction cannot be reached (dead code).
- * @throws AnalyzerException
- * if a problem occurs during the analysis.
- */
- @SuppressWarnings("unchecked")
- public Frame<V>[] analyze(final String owner, final MethodNode m)
- throws AnalyzerException {
- if ((m.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) {
- frames = (Frame<V>[]) new Frame<?>[0];
- return frames;
- }
- n = m.instructions.size();
- insns = m.instructions;
- handlers = (List<TryCatchBlockNode>[]) new List<?>[n];
- frames = (Frame<V>[]) new Frame<?>[n];
- subroutines = new Subroutine[n];
- queued = new boolean[n];
- queue = new int[n];
- top = 0;
-
- // computes exception handlers for each instruction
- for (int i = 0; i < m.tryCatchBlocks.size(); ++i) {
- TryCatchBlockNode tcb = m.tryCatchBlocks.get(i);
- int begin = insns.indexOf(tcb.start);
- int end = insns.indexOf(tcb.end);
- for (int j = begin; j < end; ++j) {
- List<TryCatchBlockNode> insnHandlers = handlers[j];
- if (insnHandlers == null) {
- insnHandlers = new ArrayList<TryCatchBlockNode>();
- handlers[j] = insnHandlers;
- }
- insnHandlers.add(tcb);
+ // Initializes the data structures for the control flow analysis.
+ Frame<V> currentFrame = computeInitialFrame(owner, method);
+ merge(0, currentFrame, null);
+ init(owner, method);
+
+ // Control flow analysis.
+ while (numInstructionsToProcess > 0) {
+ // Get and remove one instruction from the list of instructions to process.
+ int insnIndex = instructionsToProcess[--numInstructionsToProcess];
+ Frame<V> oldFrame = frames[insnIndex];
+ Subroutine subroutine = subroutines[insnIndex];
+ inInstructionsToProcess[insnIndex] = false;
+
+ // Simulate the execution of this instruction.
+ AbstractInsnNode insnNode = null;
+ try {
+ insnNode = method.instructions.get(insnIndex);
+ int insnOpcode = insnNode.getOpcode();
+ int insnType = insnNode.getType();
+
+ if (insnType == AbstractInsnNode.LABEL
+ || insnType == AbstractInsnNode.LINE
+ || insnType == AbstractInsnNode.FRAME) {
+ merge(insnIndex + 1, oldFrame, subroutine);
+ newControlFlowEdge(insnIndex, insnIndex + 1);
+ } else {
+ currentFrame.init(oldFrame).execute(insnNode, interpreter);
+ subroutine = subroutine == null ? null : new Subroutine(subroutine);
+
+ if (insnNode instanceof JumpInsnNode) {
+ JumpInsnNode jumpInsn = (JumpInsnNode) insnNode;
+ if (insnOpcode != GOTO && insnOpcode != JSR) {
+ currentFrame.initJumpTarget(insnOpcode, /* target = */ null);
+ merge(insnIndex + 1, currentFrame, subroutine);
+ newControlFlowEdge(insnIndex, insnIndex + 1);
}
- }
-
- // computes the subroutine for each instruction:
- Subroutine main = new Subroutine(null, m.maxLocals, null);
- List<AbstractInsnNode> subroutineCalls = new ArrayList<AbstractInsnNode>();
- Map<LabelNode, Subroutine> subroutineHeads = new HashMap<LabelNode, Subroutine>();
- findSubroutine(0, main, subroutineCalls);
- while (!subroutineCalls.isEmpty()) {
- JumpInsnNode jsr = (JumpInsnNode) subroutineCalls.remove(0);
- Subroutine sub = subroutineHeads.get(jsr.label);
- if (sub == null) {
- sub = new Subroutine(jsr.label, m.maxLocals, jsr);
- subroutineHeads.put(jsr.label, sub);
- findSubroutine(insns.indexOf(jsr.label), sub, subroutineCalls);
+ int jumpInsnIndex = insnList.indexOf(jumpInsn.label);
+ currentFrame.initJumpTarget(insnOpcode, jumpInsn.label);
+ if (insnOpcode == JSR) {
+ merge(
+ jumpInsnIndex,
+ currentFrame,
+ new Subroutine(jumpInsn.label, method.maxLocals, jumpInsn));
} else {
- sub.callers.add(jsr);
+ merge(jumpInsnIndex, currentFrame, subroutine);
}
- }
- for (int i = 0; i < n; ++i) {
- if (subroutines[i] != null && subroutines[i].start == null) {
- subroutines[i] = null;
+ newControlFlowEdge(insnIndex, jumpInsnIndex);
+ } else if (insnNode instanceof LookupSwitchInsnNode) {
+ LookupSwitchInsnNode lookupSwitchInsn = (LookupSwitchInsnNode) insnNode;
+ int targetInsnIndex = insnList.indexOf(lookupSwitchInsn.dflt);
+ currentFrame.initJumpTarget(insnOpcode, lookupSwitchInsn.dflt);
+ merge(targetInsnIndex, currentFrame, subroutine);
+ newControlFlowEdge(insnIndex, targetInsnIndex);
+ for (int i = 0; i < lookupSwitchInsn.labels.size(); ++i) {
+ LabelNode label = lookupSwitchInsn.labels.get(i);
+ targetInsnIndex = insnList.indexOf(label);
+ currentFrame.initJumpTarget(insnOpcode, label);
+ merge(targetInsnIndex, currentFrame, subroutine);
+ newControlFlowEdge(insnIndex, targetInsnIndex);
}
- }
-
- // initializes the data structures for the control flow analysis
- Frame<V> current = newFrame(m.maxLocals, m.maxStack);
- Frame<V> handler = newFrame(m.maxLocals, m.maxStack);
- current.setReturn(interpreter.newValue(Type.getReturnType(m.desc)));
- Type[] args = Type.getArgumentTypes(m.desc);
- int local = 0;
- if ((m.access & ACC_STATIC) == 0) {
- Type ctype = Type.getObjectType(owner);
- current.setLocal(local++, interpreter.newValue(ctype));
- }
- for (int i = 0; i < args.length; ++i) {
- current.setLocal(local++, interpreter.newValue(args[i]));
- if (args[i].getSize() == 2) {
- current.setLocal(local++, interpreter.newValue(null));
+ } else if (insnNode instanceof TableSwitchInsnNode) {
+ TableSwitchInsnNode tableSwitchInsn = (TableSwitchInsnNode) insnNode;
+ int targetInsnIndex = insnList.indexOf(tableSwitchInsn.dflt);
+ currentFrame.initJumpTarget(insnOpcode, tableSwitchInsn.dflt);
+ merge(targetInsnIndex, currentFrame, subroutine);
+ newControlFlowEdge(insnIndex, targetInsnIndex);
+ for (int i = 0; i < tableSwitchInsn.labels.size(); ++i) {
+ LabelNode label = tableSwitchInsn.labels.get(i);
+ currentFrame.initJumpTarget(insnOpcode, label);
+ targetInsnIndex = insnList.indexOf(label);
+ merge(targetInsnIndex, currentFrame, subroutine);
+ newControlFlowEdge(insnIndex, targetInsnIndex);
}
- }
- while (local < m.maxLocals) {
- current.setLocal(local++, interpreter.newValue(null));
- }
- merge(0, current, null);
-
- init(owner, m);
-
- // control flow analysis
- while (top > 0) {
- int insn = queue[--top];
- Frame<V> f = frames[insn];
- Subroutine subroutine = subroutines[insn];
- queued[insn] = false;
-
- AbstractInsnNode insnNode = null;
- try {
- insnNode = m.instructions.get(insn);
- int insnOpcode = insnNode.getOpcode();
- int insnType = insnNode.getType();
-
- if (insnType == AbstractInsnNode.LABEL
- || insnType == AbstractInsnNode.LINE
- || insnType == AbstractInsnNode.FRAME) {
- merge(insn + 1, f, subroutine);
- newControlFlowEdge(insn, insn + 1);
- } else {
- current.init(f).execute(insnNode, interpreter);
- subroutine = subroutine == null ? null : subroutine.copy();
-
- if (insnNode instanceof JumpInsnNode) {
- JumpInsnNode j = (JumpInsnNode) insnNode;
- if (insnOpcode != GOTO && insnOpcode != JSR) {
- merge(insn + 1, current, subroutine);
- newControlFlowEdge(insn, insn + 1);
- }
- int jump = insns.indexOf(j.label);
- if (insnOpcode == JSR) {
- merge(jump, current, new Subroutine(j.label,
- m.maxLocals, j));
- } else {
- merge(jump, current, subroutine);
- }
- newControlFlowEdge(insn, jump);
- } else if (insnNode instanceof LookupSwitchInsnNode) {
- LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode;
- int jump = insns.indexOf(lsi.dflt);
- merge(jump, current, subroutine);
- newControlFlowEdge(insn, jump);
- for (int j = 0; j < lsi.labels.size(); ++j) {
- LabelNode label = lsi.labels.get(j);
- jump = insns.indexOf(label);
- merge(jump, current, subroutine);
- newControlFlowEdge(insn, jump);
- }
- } else if (insnNode instanceof TableSwitchInsnNode) {
- TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode;
- int jump = insns.indexOf(tsi.dflt);
- merge(jump, current, subroutine);
- newControlFlowEdge(insn, jump);
- for (int j = 0; j < tsi.labels.size(); ++j) {
- LabelNode label = tsi.labels.get(j);
- jump = insns.indexOf(label);
- merge(jump, current, subroutine);
- newControlFlowEdge(insn, jump);
- }
- } else if (insnOpcode == RET) {
- if (subroutine == null) {
- throw new AnalyzerException(insnNode,
- "RET instruction outside of a sub routine");
- }
- for (int i = 0; i < subroutine.callers.size(); ++i) {
- JumpInsnNode caller = subroutine.callers.get(i);
- int call = insns.indexOf(caller);
- if (frames[call] != null) {
- merge(call + 1, frames[call], current,
- subroutines[call], subroutine.access);
- newControlFlowEdge(insn, call + 1);
- }
- }
- } else if (insnOpcode != ATHROW
- && (insnOpcode < IRETURN || insnOpcode > RETURN)) {
- if (subroutine != null) {
- if (insnNode instanceof VarInsnNode) {
- int var = ((VarInsnNode) insnNode).var;
- subroutine.access[var] = true;
- if (insnOpcode == LLOAD || insnOpcode == DLOAD
- || insnOpcode == LSTORE
- || insnOpcode == DSTORE) {
- subroutine.access[var + 1] = true;
- }
- } else if (insnNode instanceof IincInsnNode) {
- int var = ((IincInsnNode) insnNode).var;
- subroutine.access[var] = true;
- }
- }
- merge(insn + 1, current, subroutine);
- newControlFlowEdge(insn, insn + 1);
- }
- }
-
- List<TryCatchBlockNode> insnHandlers = handlers[insn];
- if (insnHandlers != null) {
- for (int i = 0; i < insnHandlers.size(); ++i) {
- TryCatchBlockNode tcb = insnHandlers.get(i);
- Type type;
- if (tcb.type == null) {
- type = Type.getObjectType("java/lang/Throwable");
- } else {
- type = Type.getObjectType(tcb.type);
- }
- int jump = insns.indexOf(tcb.handler);
- if (newControlFlowExceptionEdge(insn, tcb)) {
- handler.init(f);
- handler.clearStack();
- handler.push(interpreter.newValue(type));
- merge(jump, handler, subroutine);
- }
- }
- }
- } catch (AnalyzerException e) {
- throw new AnalyzerException(e.node, "Error at instruction "
- + insn + ": " + e.getMessage(), e);
- } catch (Exception e) {
- throw new AnalyzerException(insnNode, "Error at instruction "
- + insn + ": " + e.getMessage(), e);
+ } else if (insnOpcode == RET) {
+ if (subroutine == null) {
+ throw new AnalyzerException(insnNode, "RET instruction outside of a sub routine");
}
- }
-
- return frames;
- }
-
- private void findSubroutine(int insn, final Subroutine sub,
- final List<AbstractInsnNode> calls) throws AnalyzerException {
- while (true) {
- if (insn < 0 || insn >= n) {
- throw new AnalyzerException(null,
- "Execution can fall off end of the code");
+ for (int i = 0; i < subroutine.callers.size(); ++i) {
+ JumpInsnNode caller = subroutine.callers.get(i);
+ int jsrInsnIndex = insnList.indexOf(caller);
+ if (frames[jsrInsnIndex] != null) {
+ merge(
+ jsrInsnIndex + 1,
+ frames[jsrInsnIndex],
+ currentFrame,
+ subroutines[jsrInsnIndex],
+ subroutine.localsUsed);
+ newControlFlowEdge(insnIndex, jsrInsnIndex + 1);
+ }
}
- if (subroutines[insn] != null) {
- return;
- }
- subroutines[insn] = sub.copy();
- AbstractInsnNode node = insns.get(insn);
-
- // calls findSubroutine recursively on normal successors
- if (node instanceof JumpInsnNode) {
- if (node.getOpcode() == JSR) {
- // do not follow a JSR, it leads to another subroutine!
- calls.add(node);
- } else {
- JumpInsnNode jnode = (JumpInsnNode) node;
- findSubroutine(insns.indexOf(jnode.label), sub, calls);
- }
- } else if (node instanceof TableSwitchInsnNode) {
- TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
- findSubroutine(insns.indexOf(tsnode.dflt), sub, calls);
- for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
- LabelNode l = tsnode.labels.get(i);
- findSubroutine(insns.indexOf(l), sub, calls);
- }
- } else if (node instanceof LookupSwitchInsnNode) {
- LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
- findSubroutine(insns.indexOf(lsnode.dflt), sub, calls);
- for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
- LabelNode l = lsnode.labels.get(i);
- findSubroutine(insns.indexOf(l), sub, calls);
+ } else if (insnOpcode != ATHROW && (insnOpcode < IRETURN || insnOpcode > RETURN)) {
+ if (subroutine != null) {
+ if (insnNode instanceof VarInsnNode) {
+ int var = ((VarInsnNode) insnNode).var;
+ subroutine.localsUsed[var] = true;
+ if (insnOpcode == LLOAD
+ || insnOpcode == DLOAD
+ || insnOpcode == LSTORE
+ || insnOpcode == DSTORE) {
+ subroutine.localsUsed[var + 1] = true;
}
+ } else if (insnNode instanceof IincInsnNode) {
+ int var = ((IincInsnNode) insnNode).var;
+ subroutine.localsUsed[var] = true;
+ }
}
+ merge(insnIndex + 1, currentFrame, subroutine);
+ newControlFlowEdge(insnIndex, insnIndex + 1);
+ }
+ }
- // calls findSubroutine recursively on exception handler successors
- List<TryCatchBlockNode> insnHandlers = handlers[insn];
- if (insnHandlers != null) {
- for (int i = 0; i < insnHandlers.size(); ++i) {
- TryCatchBlockNode tcb = insnHandlers.get(i);
- findSubroutine(insns.indexOf(tcb.handler), sub, calls);
- }
+ List<TryCatchBlockNode> insnHandlers = handlers[insnIndex];
+ if (insnHandlers != null) {
+ for (TryCatchBlockNode tryCatchBlock : insnHandlers) {
+ Type catchType;
+ if (tryCatchBlock.type == null) {
+ catchType = Type.getObjectType("java/lang/Throwable");
+ } else {
+ catchType = Type.getObjectType(tryCatchBlock.type);
}
-
- // if insn does not falls through to the next instruction, return.
- switch (node.getOpcode()) {
- case GOTO:
- case RET:
- case TABLESWITCH:
- case LOOKUPSWITCH:
- case IRETURN:
- case LRETURN:
- case FRETURN:
- case DRETURN:
- case ARETURN:
- case RETURN:
- case ATHROW:
- return;
+ if (newControlFlowExceptionEdge(insnIndex, tryCatchBlock)) {
+ Frame<V> handler = newFrame(oldFrame);
+ handler.clearStack();
+ handler.push(interpreter.newExceptionValue(tryCatchBlock, handler, catchType));
+ merge(insnList.indexOf(tryCatchBlock.handler), handler, subroutine);
}
- insn++;
+ }
}
+ } catch (AnalyzerException e) {
+ throw new AnalyzerException(
+ e.node, "Error at instruction " + insnIndex + ": " + e.getMessage(), e);
+ } catch (RuntimeException e) {
+ // DontCheck(IllegalCatch): can't be fixed, for backward compatibility.
+ throw new AnalyzerException(
+ insnNode, "Error at instruction " + insnIndex + ": " + e.getMessage(), e);
+ }
}
- /**
- * Returns the symbolic stack frame for each instruction of the last
- * recently analyzed method.
- *
- * @return the symbolic state of the execution stack frame at each bytecode
- * instruction of the method. The size of the returned array is
- * equal to the number of instructions (and labels) of the method. A
- * given frame is <tt>null</tt> if the corresponding instruction
- * cannot be reached, or if an error occured during the analysis of
- * the method.
- */
- public Frame<V>[] getFrames() {
- return frames;
- }
+ return frames;
+ }
+
+ /**
+ * Follows the control flow graph of the currently analyzed method, starting at the given
+ * instruction index, and stores a copy of the given subroutine in {@link #subroutines} for each
+ * encountered instruction. Jumps to nested subroutines are <i>not</i> followed: instead, the
+ * corresponding instructions are put in the given list.
+ *
+ * @param insnIndex an instruction index.
+ * @param subroutine a subroutine.
+ * @param jsrInsns where the jsr instructions for nested subroutines must be put.
+ * @throws AnalyzerException if the control flow graph can fall off the end of the code.
+ */
+ private void findSubroutine(
+ final int insnIndex, final Subroutine subroutine, final List<AbstractInsnNode> jsrInsns)
+ throws AnalyzerException {
+ ArrayList<Integer> instructionIndicesToProcess = new ArrayList<Integer>();
+ instructionIndicesToProcess.add(insnIndex);
+ while (!instructionIndicesToProcess.isEmpty()) {
+ int currentInsnIndex =
+ instructionIndicesToProcess.remove(instructionIndicesToProcess.size() - 1);
+ if (currentInsnIndex < 0 || currentInsnIndex >= insnListSize) {
+ throw new AnalyzerException(null, "Execution can fall off the end of the code");
+ }
+ if (subroutines[currentInsnIndex] != null) {
+ continue;
+ }
+ subroutines[currentInsnIndex] = new Subroutine(subroutine);
+ AbstractInsnNode currentInsn = insnList.get(currentInsnIndex);
+
+ // Push the normal successors of currentInsn onto instructionIndicesToProcess.
+ if (currentInsn instanceof JumpInsnNode) {
+ if (currentInsn.getOpcode() == JSR) {
+ // Do not follow a jsr, it leads to another subroutine!
+ jsrInsns.add(currentInsn);
+ } else {
+ JumpInsnNode jumpInsn = (JumpInsnNode) currentInsn;
+ instructionIndicesToProcess.add(insnList.indexOf(jumpInsn.label));
+ }
+ } else if (currentInsn instanceof TableSwitchInsnNode) {
+ TableSwitchInsnNode tableSwitchInsn = (TableSwitchInsnNode) currentInsn;
+ findSubroutine(insnList.indexOf(tableSwitchInsn.dflt), subroutine, jsrInsns);
+ for (int i = tableSwitchInsn.labels.size() - 1; i >= 0; --i) {
+ LabelNode labelNode = tableSwitchInsn.labels.get(i);
+ instructionIndicesToProcess.add(insnList.indexOf(labelNode));
+ }
+ } else if (currentInsn instanceof LookupSwitchInsnNode) {
+ LookupSwitchInsnNode lookupSwitchInsn = (LookupSwitchInsnNode) currentInsn;
+ findSubroutine(insnList.indexOf(lookupSwitchInsn.dflt), subroutine, jsrInsns);
+ for (int i = lookupSwitchInsn.labels.size() - 1; i >= 0; --i) {
+ LabelNode labelNode = lookupSwitchInsn.labels.get(i);
+ instructionIndicesToProcess.add(insnList.indexOf(labelNode));
+ }
+ }
- /**
- * Returns the exception handlers for the given instruction.
- *
- * @param insn
- * the index of an instruction of the last recently analyzed
- * method.
- * @return a list of {@link TryCatchBlockNode} objects.
- */
- public List<TryCatchBlockNode> getHandlers(final int insn) {
- return handlers[insn];
+ // Push the exception handler successors of currentInsn onto instructionIndicesToProcess.
+ List<TryCatchBlockNode> insnHandlers = handlers[currentInsnIndex];
+ if (insnHandlers != null) {
+ for (TryCatchBlockNode tryCatchBlock : insnHandlers) {
+ instructionIndicesToProcess.add(insnList.indexOf(tryCatchBlock.handler));
+ }
+ }
+
+ // Push the next instruction, if the control flow can go from currentInsn to the next.
+ switch (currentInsn.getOpcode()) {
+ case GOTO:
+ case RET:
+ case TABLESWITCH:
+ case LOOKUPSWITCH:
+ case IRETURN:
+ case LRETURN:
+ case FRETURN:
+ case DRETURN:
+ case ARETURN:
+ case RETURN:
+ case ATHROW:
+ break;
+ default:
+ instructionIndicesToProcess.add(currentInsnIndex + 1);
+ break;
+ }
}
-
- /**
- * Initializes this analyzer. This method is called just before the
- * execution of control flow analysis loop in #analyze. The default
- * implementation of this method does nothing.
- *
- * @param owner
- * the internal name of the class to which the method belongs.
- * @param m
- * the method to be analyzed.
- * @throws AnalyzerException
- * if a problem occurs.
- */
- protected void init(String owner, MethodNode m) throws AnalyzerException {
+ }
+
+ /**
+ * Computes the initial execution stack frame of the given method.
+ *
+ * @param owner the internal name of the class to which 'method' belongs.
+ * @param method the method to be analyzed.
+ * @return the initial execution stack frame of the 'method'.
+ */
+ private Frame<V> computeInitialFrame(final String owner, final MethodNode method) {
+ Frame<V> frame = newFrame(method.maxLocals, method.maxStack);
+ int currentLocal = 0;
+ boolean isInstanceMethod = (method.access & ACC_STATIC) == 0;
+ if (isInstanceMethod) {
+ Type ownerType = Type.getObjectType(owner);
+ frame.setLocal(
+ currentLocal, interpreter.newParameterValue(isInstanceMethod, currentLocal, ownerType));
+ currentLocal++;
}
-
- /**
- * Constructs a new frame with the given size.
- *
- * @param nLocals
- * the maximum number of local variables of the frame.
- * @param nStack
- * the maximum stack size of the frame.
- * @return the created frame.
- */
- protected Frame<V> newFrame(final int nLocals, final int nStack) {
- return new Frame<V>(nLocals, nStack);
+ Type[] argumentTypes = Type.getArgumentTypes(method.desc);
+ for (Type argumentType : argumentTypes) {
+ frame.setLocal(
+ currentLocal,
+ interpreter.newParameterValue(isInstanceMethod, currentLocal, argumentType));
+ currentLocal++;
+ if (argumentType.getSize() == 2) {
+ frame.setLocal(currentLocal, interpreter.newEmptyValue(currentLocal));
+ currentLocal++;
+ }
}
-
- /**
- * Constructs a new frame that is identical to the given frame.
- *
- * @param src
- * a frame.
- * @return the created frame.
- */
- protected Frame<V> newFrame(final Frame<? extends V> src) {
- return new Frame<V>(src);
+ while (currentLocal < method.maxLocals) {
+ frame.setLocal(currentLocal, interpreter.newEmptyValue(currentLocal));
+ currentLocal++;
}
-
- /**
- * Creates a control flow graph edge. The default implementation of this
- * method does nothing. It can be overriden in order to construct the
- * control flow graph of a method (this method is called by the
- * {@link #analyze analyze} method during its visit of the method's code).
- *
- * @param insn
- * an instruction index.
- * @param successor
- * index of a successor instruction.
- */
- protected void newControlFlowEdge(final int insn, final int successor) {
+ frame.setReturn(interpreter.newReturnTypeValue(Type.getReturnType(method.desc)));
+ return frame;
+ }
+
+ /**
+ * Returns the symbolic execution stack frame for each instruction of the last analyzed method.
+ *
+ * @return the symbolic state of the execution stack frame at each bytecode instruction of the
+ * method. The size of the returned array is equal to the number of instructions (and labels)
+ * of the method. A given frame is {@literal null} if the corresponding instruction cannot be
+ * reached, or if an error occurred during the analysis of the method.
+ */
+ public Frame<V>[] getFrames() {
+ return frames;
+ }
+
+ /**
+ * Returns the exception handlers for the given instruction.
+ *
+ * @param insnIndex the index of an instruction of the last analyzed method.
+ * @return a list of {@link TryCatchBlockNode} objects.
+ */
+ public List<TryCatchBlockNode> getHandlers(final int insnIndex) {
+ return handlers[insnIndex];
+ }
+
+ /**
+ * Initializes this analyzer. This method is called just before the execution of control flow
+ * analysis loop in #analyze. The default implementation of this method does nothing.
+ *
+ * @param owner the internal name of the class to which the method belongs.
+ * @param method the method to be analyzed.
+ * @throws AnalyzerException if a problem occurs.
+ */
+ protected void init(final String owner, final MethodNode method) throws AnalyzerException {
+ // Nothing to do.
+ }
+
+ /**
+ * Constructs a new frame with the given size.
+ *
+ * @param numLocals the maximum number of local variables of the frame.
+ * @param numStack the maximum stack size of the frame.
+ * @return the created frame.
+ */
+ protected Frame<V> newFrame(final int numLocals, final int numStack) {
+ return new Frame<V>(numLocals, numStack);
+ }
+
+ /**
+ * Constructs a copy of the given frame.
+ *
+ * @param frame a frame.
+ * @return the created frame.
+ */
+ protected Frame<V> newFrame(final Frame<? extends V> frame) {
+ return new Frame<V>(frame);
+ }
+
+ /**
+ * Creates a control flow graph edge. The default implementation of this method does nothing. It
+ * can be overridden in order to construct the control flow graph of a method (this method is
+ * called by the {@link #analyze} method during its visit of the method's code).
+ *
+ * @param insnIndex an instruction index.
+ * @param successorIndex index of a successor instruction.
+ */
+ protected void newControlFlowEdge(final int insnIndex, final int successorIndex) {
+ // Nothing to do.
+ }
+
+ /**
+ * Creates a control flow graph edge corresponding to an exception handler. The default
+ * implementation of this method does nothing. It can be overridden in order to construct the
+ * control flow graph of a method (this method is called by the {@link #analyze} method during its
+ * visit of the method's code).
+ *
+ * @param insnIndex an instruction index.
+ * @param successorIndex index of a successor instruction.
+ * @return true if this edge must be considered in the data flow analysis performed by this
+ * analyzer, or false otherwise. The default implementation of this method always returns
+ * true.
+ */
+ protected boolean newControlFlowExceptionEdge(final int insnIndex, final int successorIndex) {
+ return true;
+ }
+
+ /**
+ * Creates a control flow graph edge corresponding to an exception handler. The default
+ * implementation of this method delegates to {@link #newControlFlowExceptionEdge(int, int)}. It
+ * can be overridden in order to construct the control flow graph of a method (this method is
+ * called by the {@link #analyze} method during its visit of the method's code).
+ *
+ * @param insnIndex an instruction index.
+ * @param tryCatchBlock TryCatchBlockNode corresponding to this edge.
+ * @return true if this edge must be considered in the data flow analysis performed by this
+ * analyzer, or false otherwise. The default implementation of this method delegates to {@link
+ * #newControlFlowExceptionEdge(int, int)}.
+ */
+ protected boolean newControlFlowExceptionEdge(
+ final int insnIndex, final TryCatchBlockNode tryCatchBlock) {
+ return newControlFlowExceptionEdge(insnIndex, insnList.indexOf(tryCatchBlock.handler));
+ }
+
+ // -----------------------------------------------------------------------------------------------
+
+ /**
+ * Merges the given frame and subroutine into the frame and subroutines at the given instruction
+ * index. If the frame or the subroutine at the given instruction index changes as a result of
+ * this merge, the instruction index is added to the list of instructions to process (if it is not
+ * already the case).
+ *
+ * @param insnIndex an instruction index.
+ * @param frame a frame. This frame is left unchanged by this method.
+ * @param subroutine a subroutine. This subroutine is left unchanged by this method.
+ * @throws AnalyzerException if the frames have incompatible sizes.
+ */
+ private void merge(final int insnIndex, final Frame<V> frame, final Subroutine subroutine)
+ throws AnalyzerException {
+ boolean changed;
+ Frame<V> oldFrame = frames[insnIndex];
+ if (oldFrame == null) {
+ frames[insnIndex] = newFrame(frame);
+ changed = true;
+ } else {
+ changed = oldFrame.merge(frame, interpreter);
}
-
- /**
- * Creates a control flow graph edge corresponding to an exception handler.
- * The default implementation of this method does nothing. It can be
- * overridden in order to construct the control flow graph of a method (this
- * method is called by the {@link #analyze analyze} method during its visit
- * of the method's code).
- *
- * @param insn
- * an instruction index.
- * @param successor
- * index of a successor instruction.
- * @return true if this edge must be considered in the data flow analysis
- * performed by this analyzer, or false otherwise. The default
- * implementation of this method always returns true.
- */
- protected boolean newControlFlowExceptionEdge(final int insn,
- final int successor) {
- return true;
+ Subroutine oldSubroutine = subroutines[insnIndex];
+ if (oldSubroutine == null) {
+ if (subroutine != null) {
+ subroutines[insnIndex] = new Subroutine(subroutine);
+ changed = true;
+ }
+ } else {
+ if (subroutine != null) {
+ changed |= oldSubroutine.merge(subroutine);
+ }
}
-
- /**
- * Creates a control flow graph edge corresponding to an exception handler.
- * The default implementation of this method delegates to
- * {@link #newControlFlowExceptionEdge(int, int)
- * newControlFlowExceptionEdge(int, int)}. It can be overridden in order to
- * construct the control flow graph of a method (this method is called by
- * the {@link #analyze analyze} method during its visit of the method's
- * code).
- *
- * @param insn
- * an instruction index.
- * @param tcb
- * TryCatchBlockNode corresponding to this edge.
- * @return true if this edge must be considered in the data flow analysis
- * performed by this analyzer, or false otherwise. The default
- * implementation of this method delegates to
- * {@link #newControlFlowExceptionEdge(int, int)
- * newControlFlowExceptionEdge(int, int)}.
- */
- protected boolean newControlFlowExceptionEdge(final int insn,
- final TryCatchBlockNode tcb) {
- return newControlFlowExceptionEdge(insn, insns.indexOf(tcb.handler));
+ if (changed && !inInstructionsToProcess[insnIndex]) {
+ inInstructionsToProcess[insnIndex] = true;
+ instructionsToProcess[numInstructionsToProcess++] = insnIndex;
}
-
- // -------------------------------------------------------------------------
-
- private void merge(final int insn, final Frame<V> frame,
- final Subroutine subroutine) throws AnalyzerException {
- Frame<V> oldFrame = frames[insn];
- Subroutine oldSubroutine = subroutines[insn];
- boolean changes;
-
- if (oldFrame == null) {
- frames[insn] = newFrame(frame);
- changes = true;
- } else {
- changes = oldFrame.merge(frame, interpreter);
- }
-
- if (oldSubroutine == null) {
- if (subroutine != null) {
- subroutines[insn] = subroutine.copy();
- changes = true;
- }
- } else {
- if (subroutine != null) {
- changes |= oldSubroutine.merge(subroutine);
- }
- }
- if (changes && !queued[insn]) {
- queued[insn] = true;
- queue[top++] = insn;
- }
+ }
+
+ /**
+ * Merges the given frame and subroutine into the frame and subroutines at the given instruction
+ * index (case of a RET instruction). If the frame or the subroutine at the given instruction
+ * index changes as a result of this merge, the instruction index is added to the list of
+ * instructions to process (if it is not already the case).
+ *
+ * @param insnIndex the index of an instruction immediately following a jsr instruction.
+ * @param frameBeforeJsr the execution stack frame before the jsr instruction. This frame is
+ * merged into 'frameAfterRet'.
+ * @param frameAfterRet the execution stack frame after a ret instruction of the subroutine. This
+ * frame is merged into the frame at 'insnIndex' (after it has itself been merge with
+ * 'frameBeforeJsr').
+ * @param subroutineBeforeJsr if the jsr is itself part of a subroutine (case of nested
+ * subroutine), the subroutine it belongs to.
+ * @param localsUsed the local variables read or written in the subroutine.
+ * @throws AnalyzerException if the frames have incompatible sizes.
+ */
+ private void merge(
+ final int insnIndex,
+ final Frame<V> frameBeforeJsr,
+ final Frame<V> frameAfterRet,
+ final Subroutine subroutineBeforeJsr,
+ final boolean[] localsUsed)
+ throws AnalyzerException {
+ frameAfterRet.merge(frameBeforeJsr, localsUsed);
+
+ boolean changed;
+ Frame<V> oldFrame = frames[insnIndex];
+ if (oldFrame == null) {
+ frames[insnIndex] = newFrame(frameAfterRet);
+ changed = true;
+ } else {
+ changed = oldFrame.merge(frameAfterRet, interpreter);
}
-
- private void merge(final int insn, final Frame<V> beforeJSR,
- final Frame<V> afterRET, final Subroutine subroutineBeforeJSR,
- final boolean[] access) throws AnalyzerException {
- Frame<V> oldFrame = frames[insn];
- Subroutine oldSubroutine = subroutines[insn];
- boolean changes;
-
- afterRET.merge(beforeJSR, access);
-
- if (oldFrame == null) {
- frames[insn] = newFrame(afterRET);
- changes = true;
- } else {
- changes = oldFrame.merge(afterRET, interpreter);
- }
-
- if (oldSubroutine != null && subroutineBeforeJSR != null) {
- changes |= oldSubroutine.merge(subroutineBeforeJSR);
- }
- if (changes && !queued[insn]) {
- queued[insn] = true;
- queue[top++] = insn;
- }
+ Subroutine oldSubroutine = subroutines[insnIndex];
+ if (oldSubroutine != null && subroutineBeforeJsr != null) {
+ changed |= oldSubroutine.merge(subroutineBeforeJsr);
+ }
+ if (changed && !inInstructionsToProcess[insnIndex]) {
+ inInstructionsToProcess[insnIndex] = true;
+ instructionsToProcess[numInstructionsToProcess++] = insnIndex;
}
+ }
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1c71aec7/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/AnalyzerException.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/AnalyzerException.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/AnalyzerException.java
old mode 100644
new mode 100755
index 14f5cff..fc4d0f1
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/AnalyzerException.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/AnalyzerException.java
@@ -1,62 +1,89 @@
-/***
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
+// ASM: a very small and fast Java bytecode manipulation framework
+// Copyright (c) 2000-2011 INRIA, France Telecom
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
package org.apache.tapestry5.internal.plastic.asm.tree.analysis;
import org.apache.tapestry5.internal.plastic.asm.tree.AbstractInsnNode;
/**
- * Thrown if a problem occurs during the analysis of a method.
- *
+ * An exception thrown if a problem occurs during the analysis of a method.
+ *
* @author Bing Ran
* @author Eric Bruneton
*/
-@SuppressWarnings("serial")
public class AnalyzerException extends Exception {
- public final AbstractInsnNode node;
+ private static final long serialVersionUID = 3154190448018943333L;
+
+ /** The bytecode instruction where the analysis failed. */
+ public final transient AbstractInsnNode node;
- public AnalyzerException(final AbstractInsnNode node, final String msg) {
- super(msg);
- this.node = node;
- }
+ /**
+ * Constructs a new {@link AnalyzerException}.
+ *
+ * @param insn the bytecode instruction where the analysis failed.
+ * @param message the reason why the analysis failed.
+ */
+ public AnalyzerException(final AbstractInsnNode insn, final String message) {
+ super(message);
+ this.node = insn;
+ }
- public AnalyzerException(final AbstractInsnNode node, final String msg,
- final Throwable exception) {
- super(msg, exception);
- this.node = node;
- }
+ /**
+ * Constructs a new {@link AnalyzerException}.
+ *
+ * @param insn the bytecode instruction where the analysis failed.
+ * @param message the reason why the analysis failed.
+ * @param cause the cause of the failure.
+ */
+ public AnalyzerException(
+ final AbstractInsnNode insn, final String message, final Throwable cause) {
+ super(message, cause);
+ this.node = insn;
+ }
- public AnalyzerException(final AbstractInsnNode node, final String msg,
- final Object expected, final Value encountered) {
- super((msg == null ? "Expected " : msg + ": expected ") + expected
- + ", but found " + encountered);
- this.node = node;
- }
+ /**
+ * Constructs a new {@link AnalyzerException}.
+ *
+ * @param insn the bytecode instruction where the analysis failed.
+ * @param message the reason why the analysis failed.
+ * @param expected an expected value.
+ * @param actual the actual value, different from the expected one.
+ */
+ public AnalyzerException(
+ final AbstractInsnNode insn,
+ final String message,
+ final Object expected,
+ final Value actual) {
+ super(
+ (message == null ? "Expected " : message + ": expected ")
+ + expected
+ + ", but found "
+ + actual);
+ this.node = insn;
+ }
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1c71aec7/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicInterpreter.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicInterpreter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicInterpreter.java
old mode 100644
new mode 100755
index b025094..037df4c
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicInterpreter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicInterpreter.java
@@ -1,36 +1,34 @@
-/***
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
+// ASM: a very small and fast Java bytecode manipulation framework
+// Copyright (c) 2000-2011 INRIA, France Telecom
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
package org.apache.tapestry5.internal.plastic.asm.tree.analysis;
import java.util.List;
-
+import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic;
import org.apache.tapestry5.internal.plastic.asm.Handle;
import org.apache.tapestry5.internal.plastic.asm.Opcodes;
import org.apache.tapestry5.internal.plastic.asm.Type;
@@ -45,314 +43,334 @@ import org.apache.tapestry5.internal.plastic.asm.tree.TypeInsnNode;
/**
* An {@link Interpreter} for {@link BasicValue} values.
- *
+ *
* @author Eric Bruneton
* @author Bing Ran
*/
-public class BasicInterpreter extends Interpreter<BasicValue> implements
- Opcodes {
+public class BasicInterpreter extends Interpreter<BasicValue> implements Opcodes {
- public BasicInterpreter() {
- super(ASM6);
- }
+ /**
+ * Special type used for the {@literal null} literal. This is an object reference type with
+ * descriptor 'Lnull;'.
+ */
+ public static final Type NULL_TYPE = Type.getObjectType("null");
- protected BasicInterpreter(final int api) {
- super(api);
+ /**
+ * Constructs a new {@link BasicInterpreter} for the latest ASM API version. <i>Subclasses must
+ * not use this constructor</i>. Instead, they must use the {@link #BasicInterpreter(int)}
+ * version.
+ */
+ public BasicInterpreter() {
+ super(ASM7);
+ if (getClass() != BasicInterpreter.class) {
+ throw new IllegalStateException();
}
+ }
- @Override
- public BasicValue newValue(final Type type) {
- if (type == null) {
- return BasicValue.UNINITIALIZED_VALUE;
- }
- switch (type.getSort()) {
- case Type.VOID:
- return null;
- case Type.BOOLEAN:
- case Type.CHAR:
- case Type.BYTE:
- case Type.SHORT:
- case Type.INT:
- return BasicValue.INT_VALUE;
- case Type.FLOAT:
- return BasicValue.FLOAT_VALUE;
- case Type.LONG:
- return BasicValue.LONG_VALUE;
- case Type.DOUBLE:
- return BasicValue.DOUBLE_VALUE;
- case Type.ARRAY:
- case Type.OBJECT:
- return BasicValue.REFERENCE_VALUE;
- default:
- throw new Error("Internal error");
- }
- }
+ /**
+ * Constructs a new {@link BasicInterpreter}.
+ *
+ * @param api the ASM API version supported by this interpreter. Must be one of {@link
+ * org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM4}, {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM5}, {@link
+ * org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM6} or {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM7}.
+ */
+ protected BasicInterpreter(final int api) {
+ super(api);
+ }
- @Override
- public BasicValue newOperation(final AbstractInsnNode insn)
- throws AnalyzerException {
- switch (insn.getOpcode()) {
- case ACONST_NULL:
- return newValue(Type.getObjectType("null"));
- case ICONST_M1:
- case ICONST_0:
- case ICONST_1:
- case ICONST_2:
- case ICONST_3:
- case ICONST_4:
- case ICONST_5:
- return BasicValue.INT_VALUE;
- case LCONST_0:
- case LCONST_1:
- return BasicValue.LONG_VALUE;
- case FCONST_0:
- case FCONST_1:
- case FCONST_2:
- return BasicValue.FLOAT_VALUE;
- case DCONST_0:
- case DCONST_1:
- return BasicValue.DOUBLE_VALUE;
- case BIPUSH:
- case SIPUSH:
- return BasicValue.INT_VALUE;
- case LDC:
- Object cst = ((LdcInsnNode) insn).cst;
- if (cst instanceof Integer) {
- return BasicValue.INT_VALUE;
- } else if (cst instanceof Float) {
- return BasicValue.FLOAT_VALUE;
- } else if (cst instanceof Long) {
- return BasicValue.LONG_VALUE;
- } else if (cst instanceof Double) {
- return BasicValue.DOUBLE_VALUE;
- } else if (cst instanceof String) {
- return newValue(Type.getObjectType("java/lang/String"));
- } else if (cst instanceof Type) {
- int sort = ((Type) cst).getSort();
- if (sort == Type.OBJECT || sort == Type.ARRAY) {
- return newValue(Type.getObjectType("java/lang/Class"));
- } else if (sort == Type.METHOD) {
- return newValue(Type
- .getObjectType("java/lang/invoke/MethodType"));
- } else {
- throw new IllegalArgumentException("Illegal LDC constant "
- + cst);
- }
- } else if (cst instanceof Handle) {
- return newValue(Type
- .getObjectType("java/lang/invoke/MethodHandle"));
- } else {
- throw new IllegalArgumentException("Illegal LDC constant "
- + cst);
- }
- case JSR:
- return BasicValue.RETURNADDRESS_VALUE;
- case GETSTATIC:
- return newValue(Type.getType(((FieldInsnNode) insn).desc));
- case NEW:
- return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
- default:
- throw new Error("Internal error.");
- }
+ @Override
+ public BasicValue newValue(final Type type) {
+ if (type == null) {
+ return BasicValue.UNINITIALIZED_VALUE;
}
-
- @Override
- public BasicValue copyOperation(final AbstractInsnNode insn,
- final BasicValue value) throws AnalyzerException {
- return value;
+ switch (type.getSort()) {
+ case Type.VOID:
+ return null;
+ case Type.BOOLEAN:
+ case Type.CHAR:
+ case Type.BYTE:
+ case Type.SHORT:
+ case Type.INT:
+ return BasicValue.INT_VALUE;
+ case Type.FLOAT:
+ return BasicValue.FLOAT_VALUE;
+ case Type.LONG:
+ return BasicValue.LONG_VALUE;
+ case Type.DOUBLE:
+ return BasicValue.DOUBLE_VALUE;
+ case Type.ARRAY:
+ case Type.OBJECT:
+ return BasicValue.REFERENCE_VALUE;
+ default:
+ throw new AssertionError();
}
+ }
- @Override
- public BasicValue unaryOperation(final AbstractInsnNode insn,
- final BasicValue value) throws AnalyzerException {
- switch (insn.getOpcode()) {
- case INEG:
- case IINC:
- case L2I:
- case F2I:
- case D2I:
- case I2B:
- case I2C:
- case I2S:
- return BasicValue.INT_VALUE;
- case FNEG:
- case I2F:
- case L2F:
- case D2F:
- return BasicValue.FLOAT_VALUE;
- case LNEG:
- case I2L:
- case F2L:
- case D2L:
- return BasicValue.LONG_VALUE;
- case DNEG:
- case I2D:
- case L2D:
- case F2D:
- return BasicValue.DOUBLE_VALUE;
- case IFEQ:
- case IFNE:
- case IFLT:
- case IFGE:
- case IFGT:
- case IFLE:
- case TABLESWITCH:
- case LOOKUPSWITCH:
- case IRETURN:
- case LRETURN:
- case FRETURN:
- case DRETURN:
- case ARETURN:
- case PUTSTATIC:
- return null;
- case GETFIELD:
- return newValue(Type.getType(((FieldInsnNode) insn).desc));
- case NEWARRAY:
- switch (((IntInsnNode) insn).operand) {
- case T_BOOLEAN:
- return newValue(Type.getType("[Z"));
- case T_CHAR:
- return newValue(Type.getType("[C"));
- case T_BYTE:
- return newValue(Type.getType("[B"));
- case T_SHORT:
- return newValue(Type.getType("[S"));
- case T_INT:
- return newValue(Type.getType("[I"));
- case T_FLOAT:
- return newValue(Type.getType("[F"));
- case T_DOUBLE:
- return newValue(Type.getType("[D"));
- case T_LONG:
- return newValue(Type.getType("[J"));
- default:
- throw new AnalyzerException(insn, "Invalid array type");
- }
- case ANEWARRAY:
- String desc = ((TypeInsnNode) insn).desc;
- return newValue(Type.getType("[" + Type.getObjectType(desc)));
- case ARRAYLENGTH:
- return BasicValue.INT_VALUE;
- case ATHROW:
- return null;
- case CHECKCAST:
- desc = ((TypeInsnNode) insn).desc;
- return newValue(Type.getObjectType(desc));
- case INSTANCEOF:
- return BasicValue.INT_VALUE;
- case MONITORENTER:
- case MONITOREXIT:
- case IFNULL:
- case IFNONNULL:
- return null;
- default:
- throw new Error("Internal error.");
+ @Override
+ public BasicValue newOperation(final AbstractInsnNode insn) throws AnalyzerException {
+ switch (insn.getOpcode()) {
+ case ACONST_NULL:
+ return newValue(NULL_TYPE);
+ case ICONST_M1:
+ case ICONST_0:
+ case ICONST_1:
+ case ICONST_2:
+ case ICONST_3:
+ case ICONST_4:
+ case ICONST_5:
+ return BasicValue.INT_VALUE;
+ case LCONST_0:
+ case LCONST_1:
+ return BasicValue.LONG_VALUE;
+ case FCONST_0:
+ case FCONST_1:
+ case FCONST_2:
+ return BasicValue.FLOAT_VALUE;
+ case DCONST_0:
+ case DCONST_1:
+ return BasicValue.DOUBLE_VALUE;
+ case BIPUSH:
+ case SIPUSH:
+ return BasicValue.INT_VALUE;
+ case LDC:
+ Object value = ((LdcInsnNode) insn).cst;
+ if (value instanceof Integer) {
+ return BasicValue.INT_VALUE;
+ } else if (value instanceof Float) {
+ return BasicValue.FLOAT_VALUE;
+ } else if (value instanceof Long) {
+ return BasicValue.LONG_VALUE;
+ } else if (value instanceof Double) {
+ return BasicValue.DOUBLE_VALUE;
+ } else if (value instanceof String) {
+ return newValue(Type.getObjectType("java/lang/String"));
+ } else if (value instanceof Type) {
+ int sort = ((Type) value).getSort();
+ if (sort == Type.OBJECT || sort == Type.ARRAY) {
+ return newValue(Type.getObjectType("java/lang/Class"));
+ } else if (sort == Type.METHOD) {
+ return newValue(Type.getObjectType("java/lang/invoke/MethodType"));
+ } else {
+ throw new AnalyzerException(insn, "Illegal LDC value " + value);
+ }
+ } else if (value instanceof Handle) {
+ return newValue(Type.getObjectType("java/lang/invoke/MethodHandle"));
+ } else if (value instanceof ConstantDynamic) {
+ return newValue(Type.getType(((ConstantDynamic) value).getDescriptor()));
+ } else {
+ throw new AnalyzerException(insn, "Illegal LDC value " + value);
}
+ case JSR:
+ return BasicValue.RETURNADDRESS_VALUE;
+ case GETSTATIC:
+ return newValue(Type.getType(((FieldInsnNode) insn).desc));
+ case NEW:
+ return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
+ default:
+ throw new AssertionError();
}
+ }
+
+ @Override
+ public BasicValue copyOperation(final AbstractInsnNode insn, final BasicValue value)
+ throws AnalyzerException {
+ return value;
+ }
- @Override
- public BasicValue binaryOperation(final AbstractInsnNode insn,
- final BasicValue value1, final BasicValue value2)
- throws AnalyzerException {
- switch (insn.getOpcode()) {
- case IALOAD:
- case BALOAD:
- case CALOAD:
- case SALOAD:
- case IADD:
- case ISUB:
- case IMUL:
- case IDIV:
- case IREM:
- case ISHL:
- case ISHR:
- case IUSHR:
- case IAND:
- case IOR:
- case IXOR:
- return BasicValue.INT_VALUE;
- case FALOAD:
- case FADD:
- case FSUB:
- case FMUL:
- case FDIV:
- case FREM:
- return BasicValue.FLOAT_VALUE;
- case LALOAD:
- case LADD:
- case LSUB:
- case LMUL:
- case LDIV:
- case LREM:
- case LSHL:
- case LSHR:
- case LUSHR:
- case LAND:
- case LOR:
- case LXOR:
- return BasicValue.LONG_VALUE;
- case DALOAD:
- case DADD:
- case DSUB:
- case DMUL:
- case DDIV:
- case DREM:
- return BasicValue.DOUBLE_VALUE;
- case AALOAD:
- return BasicValue.REFERENCE_VALUE;
- case LCMP:
- case FCMPL:
- case FCMPG:
- case DCMPL:
- case DCMPG:
- return BasicValue.INT_VALUE;
- 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 PUTFIELD:
- return null;
- default:
- throw new Error("Internal error.");
+ @Override
+ public BasicValue unaryOperation(final AbstractInsnNode insn, final BasicValue value)
+ throws AnalyzerException {
+ switch (insn.getOpcode()) {
+ case INEG:
+ case IINC:
+ case L2I:
+ case F2I:
+ case D2I:
+ case I2B:
+ case I2C:
+ case I2S:
+ return BasicValue.INT_VALUE;
+ case FNEG:
+ case I2F:
+ case L2F:
+ case D2F:
+ return BasicValue.FLOAT_VALUE;
+ case LNEG:
+ case I2L:
+ case F2L:
+ case D2L:
+ return BasicValue.LONG_VALUE;
+ case DNEG:
+ case I2D:
+ case L2D:
+ case F2D:
+ return BasicValue.DOUBLE_VALUE;
+ case IFEQ:
+ case IFNE:
+ case IFLT:
+ case IFGE:
+ case IFGT:
+ case IFLE:
+ case TABLESWITCH:
+ case LOOKUPSWITCH:
+ case IRETURN:
+ case LRETURN:
+ case FRETURN:
+ case DRETURN:
+ case ARETURN:
+ case PUTSTATIC:
+ return null;
+ case GETFIELD:
+ return newValue(Type.getType(((FieldInsnNode) insn).desc));
+ case NEWARRAY:
+ switch (((IntInsnNode) insn).operand) {
+ case T_BOOLEAN:
+ return newValue(Type.getType("[Z"));
+ case T_CHAR:
+ return newValue(Type.getType("[C"));
+ case T_BYTE:
+ return newValue(Type.getType("[B"));
+ case T_SHORT:
+ return newValue(Type.getType("[S"));
+ case T_INT:
+ return newValue(Type.getType("[I"));
+ case T_FLOAT:
+ return newValue(Type.getType("[F"));
+ case T_DOUBLE:
+ return newValue(Type.getType("[D"));
+ case T_LONG:
+ return newValue(Type.getType("[J"));
+ default:
+ break;
}
+ throw new AnalyzerException(insn, "Invalid array type");
+ case ANEWARRAY:
+ return newValue(Type.getType("[" + Type.getObjectType(((TypeInsnNode) insn).desc)));
+ case ARRAYLENGTH:
+ return BasicValue.INT_VALUE;
+ case ATHROW:
+ return null;
+ case CHECKCAST:
+ return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
+ case INSTANCEOF:
+ return BasicValue.INT_VALUE;
+ case MONITORENTER:
+ case MONITOREXIT:
+ case IFNULL:
+ case IFNONNULL:
+ return null;
+ default:
+ throw new AssertionError();
}
+ }
- @Override
- public BasicValue ternaryOperation(final AbstractInsnNode insn,
- final BasicValue value1, final BasicValue value2,
- final BasicValue value3) throws AnalyzerException {
+ @Override
+ public BasicValue binaryOperation(
+ final AbstractInsnNode insn, final BasicValue value1, final BasicValue value2)
+ throws AnalyzerException {
+ switch (insn.getOpcode()) {
+ case IALOAD:
+ case BALOAD:
+ case CALOAD:
+ case SALOAD:
+ case IADD:
+ case ISUB:
+ case IMUL:
+ case IDIV:
+ case IREM:
+ case ISHL:
+ case ISHR:
+ case IUSHR:
+ case IAND:
+ case IOR:
+ case IXOR:
+ return BasicValue.INT_VALUE;
+ case FALOAD:
+ case FADD:
+ case FSUB:
+ case FMUL:
+ case FDIV:
+ case FREM:
+ return BasicValue.FLOAT_VALUE;
+ case LALOAD:
+ case LADD:
+ case LSUB:
+ case LMUL:
+ case LDIV:
+ case LREM:
+ case LSHL:
+ case LSHR:
+ case LUSHR:
+ case LAND:
+ case LOR:
+ case LXOR:
+ return BasicValue.LONG_VALUE;
+ case DALOAD:
+ case DADD:
+ case DSUB:
+ case DMUL:
+ case DDIV:
+ case DREM:
+ return BasicValue.DOUBLE_VALUE;
+ case AALOAD:
+ return BasicValue.REFERENCE_VALUE;
+ case LCMP:
+ case FCMPL:
+ case FCMPG:
+ case DCMPL:
+ case DCMPG:
+ return BasicValue.INT_VALUE;
+ 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 PUTFIELD:
return null;
+ default:
+ throw new AssertionError();
}
+ }
- @Override
- public BasicValue naryOperation(final AbstractInsnNode insn,
- final List<? extends BasicValue> values) throws AnalyzerException {
- int opcode = insn.getOpcode();
- if (opcode == MULTIANEWARRAY) {
- return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc));
- } else if (opcode == INVOKEDYNAMIC) {
- return newValue(Type
- .getReturnType(((InvokeDynamicInsnNode) insn).desc));
- } else {
- return newValue(Type.getReturnType(((MethodInsnNode) insn).desc));
- }
- }
+ @Override
+ public BasicValue ternaryOperation(
+ final AbstractInsnNode insn,
+ final BasicValue value1,
+ final BasicValue value2,
+ final BasicValue value3)
+ throws AnalyzerException {
+ return null;
+ }
- @Override
- public void returnOperation(final AbstractInsnNode insn,
- final BasicValue value, final BasicValue expected)
- throws AnalyzerException {
+ @Override
+ public BasicValue naryOperation(
+ final AbstractInsnNode insn, final List<? extends BasicValue> values)
+ throws AnalyzerException {
+ int opcode = insn.getOpcode();
+ if (opcode == MULTIANEWARRAY) {
+ return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc));
+ } else if (opcode == INVOKEDYNAMIC) {
+ return newValue(Type.getReturnType(((InvokeDynamicInsnNode) insn).desc));
+ } else {
+ return newValue(Type.getReturnType(((MethodInsnNode) insn).desc));
}
+ }
- @Override
- public BasicValue merge(final BasicValue v, final BasicValue w) {
- if (!v.equals(w)) {
- return BasicValue.UNINITIALIZED_VALUE;
- }
- return v;
+ @Override
+ public void returnOperation(
+ final AbstractInsnNode insn, final BasicValue value, final BasicValue expected)
+ throws AnalyzerException {
+ // Nothing to do.
+ }
+
+ @Override
+ public BasicValue merge(final BasicValue value1, final BasicValue value2) {
+ if (!value1.equals(value2)) {
+ return BasicValue.UNINITIALIZED_VALUE;
}
+ return value1;
+ }
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1c71aec7/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicValue.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicValue.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicValue.java
old mode 100644
new mode 100755
index 44b0704..71c3d5e
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicValue.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicValue.java
@@ -1,111 +1,129 @@
-/***
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
+// ASM: a very small and fast Java bytecode manipulation framework
+// Copyright (c) 2000-2011 INRIA, France Telecom
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
package org.apache.tapestry5.internal.plastic.asm.tree.analysis;
import org.apache.tapestry5.internal.plastic.asm.Type;
/**
- * A {@link Value} that is represented by its type in a seven types type system.
- * This type system distinguishes the UNINITIALZED, INT, FLOAT, LONG, DOUBLE,
- * REFERENCE and RETURNADDRESS types.
- *
+ * A {@link Value} that is represented with its type in a seven types type system. This type system
+ * distinguishes the UNINITIALZED, INT, FLOAT, LONG, DOUBLE, REFERENCE and RETURNADDRESS types.
+ *
* @author Eric Bruneton
*/
public class BasicValue implements Value {
- public static final BasicValue UNINITIALIZED_VALUE = new BasicValue(null);
-
- public static final BasicValue INT_VALUE = new BasicValue(Type.INT_TYPE);
-
- public static final BasicValue FLOAT_VALUE = new BasicValue(Type.FLOAT_TYPE);
-
- public static final BasicValue LONG_VALUE = new BasicValue(Type.LONG_TYPE);
-
- public static final BasicValue DOUBLE_VALUE = new BasicValue(
- Type.DOUBLE_TYPE);
-
- public static final BasicValue REFERENCE_VALUE = new BasicValue(
- Type.getObjectType("java/lang/Object"));
-
- public static final BasicValue RETURNADDRESS_VALUE = new BasicValue(
- Type.VOID_TYPE);
-
- private final Type type;
-
- public BasicValue(final Type type) {
- this.type = type;
+ /** An uninitialized value. */
+ public static final BasicValue UNINITIALIZED_VALUE = new BasicValue(null);
+
+ /** A byte, boolean, char, short, or int value. */
+ public static final BasicValue INT_VALUE = new BasicValue(Type.INT_TYPE);
+
+ /** A float value. */
+ public static final BasicValue FLOAT_VALUE = new BasicValue(Type.FLOAT_TYPE);
+
+ /** A long value. */
+ public static final BasicValue LONG_VALUE = new BasicValue(Type.LONG_TYPE);
+
+ /** A double value. */
+ public static final BasicValue DOUBLE_VALUE = new BasicValue(Type.DOUBLE_TYPE);
+
+ /** An object or array reference value. */
+ public static final BasicValue REFERENCE_VALUE =
+ new BasicValue(Type.getObjectType("java/lang/Object"));
+
+ /** A return address value (produced by a jsr instruction). */
+ public static final BasicValue RETURNADDRESS_VALUE = new BasicValue(Type.VOID_TYPE);
+
+ /** The {@link Type} of this value, or {@literal null} for uninitialized values. */
+ private final Type type;
+
+ /**
+ * Constructs a new {@link BasicValue} of the given type.
+ *
+ * @param type the value type.
+ */
+ public BasicValue(final Type type) {
+ this.type = type;
+ }
+
+ /**
+ * Returns the {@link Type} of this value.
+ *
+ * @return the {@link Type} of this value.
+ */
+ public Type getType() {
+ return type;
+ }
+
+ @Override
+ public int getSize() {
+ return type == Type.LONG_TYPE || type == Type.DOUBLE_TYPE ? 2 : 1;
+ }
+
+ /**
+ * Returns whether this value corresponds to an object or array reference.
+ *
+ * @return whether this value corresponds to an object or array reference.
+ */
+ public boolean isReference() {
+ return type != null && (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY);
+ }
+
+ @Override
+ public boolean equals(final Object value) {
+ if (value == this) {
+ return true;
+ } else if (value instanceof BasicValue) {
+ if (type == null) {
+ return ((BasicValue) value).type == null;
+ } else {
+ return type.equals(((BasicValue) value).type);
+ }
+ } else {
+ return false;
}
-
- public Type getType() {
- return type;
- }
-
- public int getSize() {
- return type == Type.LONG_TYPE || type == Type.DOUBLE_TYPE ? 2 : 1;
- }
-
- public boolean isReference() {
- return type != null
- && (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY);
- }
-
- @Override
- public boolean equals(final Object value) {
- if (value == this) {
- return true;
- } else if (value instanceof BasicValue) {
- if (type == null) {
- return ((BasicValue) value).type == null;
- } else {
- return type.equals(((BasicValue) value).type);
- }
- } else {
- return false;
- }
- }
-
- @Override
- public int hashCode() {
- return type == null ? 0 : type.hashCode();
- }
-
- @Override
- public String toString() {
- if (this == UNINITIALIZED_VALUE) {
- return ".";
- } else if (this == RETURNADDRESS_VALUE) {
- return "A";
- } else if (this == REFERENCE_VALUE) {
- return "R";
- } else {
- return type.getDescriptor();
- }
+ }
+
+ @Override
+ public int hashCode() {
+ return type == null ? 0 : type.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ if (this == UNINITIALIZED_VALUE) {
+ return ".";
+ } else if (this == RETURNADDRESS_VALUE) {
+ return "A";
+ } else if (this == REFERENCE_VALUE) {
+ return "R";
+ } else {
+ return type.getDescriptor();
}
+ }
}