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