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(); } + } }
