http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1c71aec7/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AnalyzerAdapter.java ---------------------------------------------------------------------- diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AnalyzerAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AnalyzerAdapter.java old mode 100644 new mode 100755 index 5ff7100..b541ecd --- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AnalyzerAdapter.java +++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AnalyzerAdapter.java @@ -1,39 +1,37 @@ -/*** - * 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.commons; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - +import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic; import org.apache.tapestry5.internal.plastic.asm.Handle; import org.apache.tapestry5.internal.plastic.asm.Label; import org.apache.tapestry5.internal.plastic.asm.MethodVisitor; @@ -41,909 +39,899 @@ import org.apache.tapestry5.internal.plastic.asm.Opcodes; import org.apache.tapestry5.internal.plastic.asm.Type; /** - * A {@link MethodVisitor} that keeps track of stack map frame changes between - * {@link #visitFrame(int, int, Object[], int, Object[]) visitFrame} calls. This - * adapter must be used with the - * {@link org.objectweb.asm.ClassReader#EXPAND_FRAMES} option. Each - * visit<i>X</i> instruction delegates to the next visitor in the chain, if any, - * and then simulates the effect of this instruction on the stack map frame, - * represented by {@link #locals} and {@link #stack}. The next visitor in the - * chain can get the state of the stack map frame <i>before</i> each instruction - * by reading the value of these fields in its visit<i>X</i> methods (this - * requires a reference to the AnalyzerAdapter that is before it in the chain). - * If this adapter is used with a class that does not contain stack map table - * attributes (i.e., pre Java 6 classes) then this adapter may not be able to - * compute the stack map frame for each instruction. In this case no exception - * is thrown but the {@link #locals} and {@link #stack} fields will be null for - * these instructions. - * + * A {@link MethodVisitor} that keeps track of stack map frame changes between {@link + * #visitFrame(int, int, Object[], int, Object[])} calls. This adapter must be used with the {@link + * org.apache.tapestry5.internal.plastic.asm.ClassReader#EXPAND_FRAMES} option. Each visit<i>X</i> instruction delegates to + * the next visitor in the chain, if any, and then simulates the effect of this instruction on the + * stack map frame, represented by {@link #locals} and {@link #stack}. The next visitor in the chain + * can get the state of the stack map frame <i>before</i> each instruction by reading the value of + * these fields in its visit<i>X</i> methods (this requires a reference to the AnalyzerAdapter that + * is before it in the chain). If this adapter is used with a class that does not contain stack map + * table attributes (i.e., pre Java 6 classes) then this adapter may not be able to compute the + * stack map frame for each instruction. In this case no exception is thrown but the {@link #locals} + * and {@link #stack} fields will be null for these instructions. + * * @author Eric Bruneton */ public class AnalyzerAdapter extends MethodVisitor { - /** - * <code>List</code> of the local variable slots for current execution - * frame. Primitive types are represented by {@link Opcodes#TOP}, - * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, - * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or - * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by - * two elements, the second one being TOP). Reference types are represented - * by String objects (representing internal names), and uninitialized types - * by Label objects (this label designates the NEW instruction that created - * this uninitialized value). This field is <tt>null</tt> for unreachable - * instructions. - */ - public List<Object> locals; - - /** - * <code>List</code> of the operand stack slots for current execution frame. - * Primitive types are represented by {@link Opcodes#TOP}, - * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, - * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or - * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by - * two elements, the second one being TOP). Reference types are represented - * by String objects (representing internal names), and uninitialized types - * by Label objects (this label designates the NEW instruction that created - * this uninitialized value). This field is <tt>null</tt> for unreachable - * instructions. - */ - public List<Object> stack; - - /** - * The labels that designate the next instruction to be visited. May be - * <tt>null</tt>. - */ - private List<Label> labels; - - /** - * Information about uninitialized types in the current execution frame. - * This map associates internal names to Label objects. Each label - * designates a NEW instruction that created the currently uninitialized - * types, and the associated internal name represents the NEW operand, i.e. - * the final, initialized type value. - */ - public Map<Object, Object> uninitializedTypes; - - /** - * The maximum stack size of this method. - */ - private int maxStack; - - /** - * The maximum number of local variables of this method. - */ - private int maxLocals; - - /** - * The owner's class name. - */ - private String owner; - - /** - * Creates a new {@link AnalyzerAdapter}. <i>Subclasses must not use this - * constructor</i>. Instead, they must use the - * {@link #AnalyzerAdapter(int, String, int, String, String, MethodVisitor)} - * version. - * - * @param owner - * the owner's class name. - * @param access - * the method's access flags (see {@link Opcodes}). - * @param name - * the method's name. - * @param desc - * the method's descriptor (see {@link Type Type}). - * @param mv - * the method visitor to which this adapter delegates calls. May - * be <tt>null</tt>. - * @throws IllegalStateException - * If a subclass calls this constructor. - */ - public AnalyzerAdapter(final String owner, final int access, - final String name, final String desc, final MethodVisitor mv) { - this(Opcodes.ASM6, owner, access, name, desc, mv); - if (getClass() != AnalyzerAdapter.class) { - throw new IllegalStateException(); - } + /** + * The local variable slots for the current execution frame. Primitive types are represented by + * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, + * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link Opcodes#UNINITIALIZED_THIS} (long and + * double are represented by two elements, the second one being TOP). Reference types are + * represented by String objects (representing internal names), and uninitialized types by Label + * objects (this label designates the NEW instruction that created this uninitialized value). This + * field is {@literal null} for unreachable instructions. + */ + public List<Object> locals; + + /** + * The operand stack slots for the current execution frame. Primitive types are represented by + * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, + * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link Opcodes#UNINITIALIZED_THIS} (long and + * double are represented by two elements, the second one being TOP). Reference types are + * represented by String objects (representing internal names), and uninitialized types by Label + * objects (this label designates the NEW instruction that created this uninitialized value). This + * field is {@literal null} for unreachable instructions. + */ + public List<Object> stack; + + /** The labels that designate the next instruction to be visited. May be {@literal null}. */ + private List<Label> labels; + + /** + * The uninitialized types in the current execution frame. This map associates internal names to + * Label objects. Each label designates a NEW instruction that created the currently uninitialized + * types, and the associated internal name represents the NEW operand, i.e. the final, initialized + * type value. + */ + public Map<Object, Object> uninitializedTypes; + + /** The maximum stack size of this method. */ + private int maxStack; + + /** The maximum number of local variables of this method. */ + private int maxLocals; + + /** The owner's class name. */ + private String owner; + + /** + * Constructs a new {@link AnalyzerAdapter}. <i>Subclasses must not use this constructor</i>. + * Instead, they must use the {@link #AnalyzerAdapter(int, String, int, String, String, + * MethodVisitor)} version. + * + * @param owner the owner's class name. + * @param access the method's access flags (see {@link Opcodes}). + * @param name the method's name. + * @param descriptor the method's descriptor (see {@link Type}). + * @param methodVisitor the method visitor to which this adapter delegates calls. May be {@literal + * null}. + * @throws IllegalStateException If a subclass calls this constructor. + */ + public AnalyzerAdapter( + final String owner, + final int access, + final String name, + final String descriptor, + final MethodVisitor methodVisitor) { + this(Opcodes.ASM7, owner, access, name, descriptor, methodVisitor); + if (getClass() != AnalyzerAdapter.class) { + throw new IllegalStateException(); } - - /** - * Creates a new {@link AnalyzerAdapter}. - * - * @param api - * the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - * @param owner - * the owner's class name. - * @param access - * the method's access flags (see {@link Opcodes}). - * @param name - * the method's name. - * @param desc - * the method's descriptor (see {@link Type Type}). - * @param mv - * the method visitor to which this adapter delegates calls. May - * be <tt>null</tt>. - */ - protected AnalyzerAdapter(final int api, final String owner, - final int access, final String name, final String desc, - final MethodVisitor mv) { - super(api, mv); - this.owner = owner; - locals = new ArrayList<Object>(); - stack = new ArrayList<Object>(); - uninitializedTypes = new HashMap<Object, Object>(); - - if ((access & Opcodes.ACC_STATIC) == 0) { - if ("<init>".equals(name)) { - locals.add(Opcodes.UNINITIALIZED_THIS); - } else { - locals.add(owner); - } - } - Type[] types = Type.getArgumentTypes(desc); - for (int i = 0; i < types.length; ++i) { - Type type = types[i]; - switch (type.getSort()) { - case Type.BOOLEAN: - case Type.CHAR: - case Type.BYTE: - case Type.SHORT: - case Type.INT: - locals.add(Opcodes.INTEGER); - break; - case Type.FLOAT: - locals.add(Opcodes.FLOAT); - break; - case Type.LONG: - locals.add(Opcodes.LONG); - locals.add(Opcodes.TOP); - break; - case Type.DOUBLE: - locals.add(Opcodes.DOUBLE); - locals.add(Opcodes.TOP); - break; - case Type.ARRAY: - locals.add(types[i].getDescriptor()); - break; - // case Type.OBJECT: - default: - locals.add(types[i].getInternalName()); - } - } - maxLocals = locals.size(); + } + + /** + * Constructs a new {@link AnalyzerAdapter}. + * + * @param api the ASM API version implemented by this visitor. Must be one of {@link + * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}. + * @param owner the owner's class name. + * @param access the method's access flags (see {@link Opcodes}). + * @param name the method's name. + * @param descriptor the method's descriptor (see {@link Type}). + * @param methodVisitor the method visitor to which this adapter delegates calls. May be {@literal + * null}. + */ + protected AnalyzerAdapter( + final int api, + final String owner, + final int access, + final String name, + final String descriptor, + final MethodVisitor methodVisitor) { + super(api, methodVisitor); + this.owner = owner; + locals = new ArrayList<Object>(); + stack = new ArrayList<Object>(); + uninitializedTypes = new HashMap<Object, Object>(); + + if ((access & Opcodes.ACC_STATIC) == 0) { + if ("<init>".equals(name)) { + locals.add(Opcodes.UNINITIALIZED_THIS); + } else { + locals.add(owner); + } } - - @Override - public void visitFrame(final int type, final int nLocal, - final Object[] local, final int nStack, final Object[] stack) { - if (type != Opcodes.F_NEW) { // uncompressed frame - throw new IllegalStateException( - "ClassReader.accept() should be called with EXPAND_FRAMES flag"); - } - - if (mv != null) { - mv.visitFrame(type, nLocal, local, nStack, stack); - } - - if (this.locals != null) { - this.locals.clear(); - this.stack.clear(); - } else { - this.locals = new ArrayList<Object>(); - this.stack = new ArrayList<Object>(); - } - visitFrameTypes(nLocal, local, this.locals); - visitFrameTypes(nStack, stack, this.stack); - maxStack = Math.max(maxStack, this.stack.size()); + for (Type argumentType : Type.getArgumentTypes(descriptor)) { + switch (argumentType.getSort()) { + case Type.BOOLEAN: + case Type.CHAR: + case Type.BYTE: + case Type.SHORT: + case Type.INT: + locals.add(Opcodes.INTEGER); + break; + case Type.FLOAT: + locals.add(Opcodes.FLOAT); + break; + case Type.LONG: + locals.add(Opcodes.LONG); + locals.add(Opcodes.TOP); + break; + case Type.DOUBLE: + locals.add(Opcodes.DOUBLE); + locals.add(Opcodes.TOP); + break; + case Type.ARRAY: + locals.add(argumentType.getDescriptor()); + break; + case Type.OBJECT: + locals.add(argumentType.getInternalName()); + break; + default: + throw new AssertionError(); + } } - - private static void visitFrameTypes(final int n, final Object[] types, - final List<Object> result) { - for (int i = 0; i < n; ++i) { - Object type = types[i]; - result.add(type); - if (type == Opcodes.LONG || type == Opcodes.DOUBLE) { - result.add(Opcodes.TOP); - } - } + maxLocals = locals.size(); + } + + @Override + public void visitFrame( + final int type, + final int numLocal, + final Object[] local, + final int numStack, + final Object[] stack) { + if (type != Opcodes.F_NEW) { // Uncompressed frame. + throw new IllegalArgumentException( + "AnalyzerAdapter only accepts expanded frames (see ClassReader.EXPAND_FRAMES)"); } - @Override - public void visitInsn(final int opcode) { - if (mv != null) { - mv.visitInsn(opcode); - } - execute(opcode, 0, null); - if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) - || opcode == Opcodes.ATHROW) { - this.locals = null; - this.stack = null; - } - } + super.visitFrame(type, numLocal, local, numStack, stack); - @Override - public void visitIntInsn(final int opcode, final int operand) { - if (mv != null) { - mv.visitIntInsn(opcode, operand); - } - execute(opcode, operand, null); + if (this.locals != null) { + this.locals.clear(); + this.stack.clear(); + } else { + this.locals = new ArrayList<Object>(); + this.stack = new ArrayList<Object>(); } - - @Override - public void visitVarInsn(final int opcode, final int var) { - if (mv != null) { - mv.visitVarInsn(opcode, var); - } - execute(opcode, var, null); + visitFrameTypes(numLocal, local, this.locals); + visitFrameTypes(numStack, stack, this.stack); + maxLocals = Math.max(maxLocals, this.locals.size()); + maxStack = Math.max(maxStack, this.stack.size()); + } + + private static void visitFrameTypes( + final int numTypes, final Object[] frameTypes, final List<Object> result) { + for (int i = 0; i < numTypes; ++i) { + Object frameType = frameTypes[i]; + result.add(frameType); + if (frameType == Opcodes.LONG || frameType == Opcodes.DOUBLE) { + result.add(Opcodes.TOP); + } } - - @Override - public void visitTypeInsn(final int opcode, final String type) { - if (opcode == Opcodes.NEW) { - if (labels == null) { - Label l = new Label(); - labels = new ArrayList<Label>(3); - labels.add(l); - if (mv != null) { - mv.visitLabel(l); - } - } - for (int i = 0; i < labels.size(); ++i) { - uninitializedTypes.put(labels.get(i), type); - } - } - if (mv != null) { - mv.visitTypeInsn(opcode, type); - } - execute(opcode, 0, type); + } + + @Override + public void visitInsn(final int opcode) { + super.visitInsn(opcode); + execute(opcode, 0, null); + if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) { + this.locals = null; + this.stack = null; } - - @Override - public void visitFieldInsn(final int opcode, final String owner, - final String name, final String desc) { + } + + @Override + public void visitIntInsn(final int opcode, final int operand) { + super.visitIntInsn(opcode, operand); + execute(opcode, operand, null); + } + + @Override + public void visitVarInsn(final int opcode, final int var) { + super.visitVarInsn(opcode, var); + boolean isLongOrDouble = + opcode == Opcodes.LLOAD + || opcode == Opcodes.DLOAD + || opcode == Opcodes.LSTORE + || opcode == Opcodes.DSTORE; + maxLocals = Math.max(maxLocals, var + (isLongOrDouble ? 2 : 1)); + execute(opcode, var, null); + } + + @Override + public void visitTypeInsn(final int opcode, final String type) { + if (opcode == Opcodes.NEW) { + if (labels == null) { + Label label = new Label(); + labels = new ArrayList<Label>(3); + labels.add(label); if (mv != null) { - mv.visitFieldInsn(opcode, owner, name, desc); + mv.visitLabel(label); } - execute(opcode, 0, desc); + } + for (Label label : labels) { + uninitializedTypes.put(label, type); + } } - - @Deprecated - @Override - public void visitMethodInsn(final int opcode, final String owner, - final String name, final String desc) { - if (api >= Opcodes.ASM5) { - super.visitMethodInsn(opcode, owner, name, desc); - return; - } - doVisitMethodInsn(opcode, owner, name, desc, - opcode == Opcodes.INVOKEINTERFACE); + super.visitTypeInsn(opcode, type); + execute(opcode, 0, type); + } + + @Override + public void visitFieldInsn( + final int opcode, final String owner, final String name, final String descriptor) { + super.visitFieldInsn(opcode, owner, name, descriptor); + execute(opcode, 0, descriptor); + } + + /** + * Deprecated. + * + * @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead. + */ + @Deprecated + @Override + public void visitMethodInsn( + final int opcode, final String owner, final String name, final String descriptor) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, descriptor); + return; } - - @Override - public void visitMethodInsn(final int opcode, final String owner, - final String name, final String desc, final boolean itf) { - if (api < Opcodes.ASM5) { - super.visitMethodInsn(opcode, owner, name, desc, itf); - return; - } - doVisitMethodInsn(opcode, owner, name, desc, itf); + doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn( + final int opcode, + final String owner, + final String name, + final String descriptor, + final boolean isInterface) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); + return; } - - private void doVisitMethodInsn(int opcode, final String owner, - final String name, final String desc, final boolean itf) { - if (mv != null) { - mv.visitMethodInsn(opcode, owner, name, desc, itf); - } - if (this.locals == null) { - labels = null; - return; - } - pop(desc); - if (opcode != Opcodes.INVOKESTATIC) { - Object t = pop(); - if (opcode == Opcodes.INVOKESPECIAL && name.charAt(0) == '<') { - Object u; - if (t == Opcodes.UNINITIALIZED_THIS) { - u = this.owner; - } else { - u = uninitializedTypes.get(t); - } - for (int i = 0; i < locals.size(); ++i) { - if (locals.get(i) == t) { - locals.set(i, u); - } - } - for (int i = 0; i < stack.size(); ++i) { - if (stack.get(i) == t) { - stack.set(i, u); - } - } - } - } - pushDesc(desc); - labels = null; + doVisitMethodInsn(opcode, owner, name, descriptor, isInterface); + } + + private void doVisitMethodInsn( + final int opcode, + final String owner, + final String name, + final String descriptor, + final boolean isInterface) { + if (mv != null) { + mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface); } - - @Override - public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, - Object... bsmArgs) { - if (mv != null) { - mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); - } - if (this.locals == null) { - labels = null; - return; - } - pop(desc); - pushDesc(desc); - labels = null; + if (this.locals == null) { + labels = null; + return; } - - @Override - public void visitJumpInsn(final int opcode, final Label label) { - if (mv != null) { - mv.visitJumpInsn(opcode, label); + pop(descriptor); + if (opcode != Opcodes.INVOKESTATIC) { + Object value = pop(); + if (opcode == Opcodes.INVOKESPECIAL && name.equals("<init>")) { + Object initializedValue; + if (value == Opcodes.UNINITIALIZED_THIS) { + initializedValue = this.owner; + } else { + initializedValue = uninitializedTypes.get(value); } - execute(opcode, 0, null); - if (opcode == Opcodes.GOTO) { - this.locals = null; - this.stack = null; + for (int i = 0; i < locals.size(); ++i) { + if (locals.get(i) == value) { + locals.set(i, initializedValue); + } } - } - - @Override - public void visitLabel(final Label label) { - if (mv != null) { - mv.visitLabel(label); - } - if (labels == null) { - labels = new ArrayList<Label>(3); + for (int i = 0; i < stack.size(); ++i) { + if (stack.get(i) == value) { + stack.set(i, initializedValue); + } } - labels.add(label); + } } - - @Override - public void visitLdcInsn(final Object cst) { - if (mv != null) { - mv.visitLdcInsn(cst); - } - if (this.locals == null) { - labels = null; - return; - } - if (cst instanceof Integer) { - push(Opcodes.INTEGER); - } else if (cst instanceof Long) { - push(Opcodes.LONG); - push(Opcodes.TOP); - } else if (cst instanceof Float) { - push(Opcodes.FLOAT); - } else if (cst instanceof Double) { - push(Opcodes.DOUBLE); - push(Opcodes.TOP); - } else if (cst instanceof String) { - push("java/lang/String"); - } else if (cst instanceof Type) { - int sort = ((Type) cst).getSort(); - if (sort == Type.OBJECT || sort == Type.ARRAY) { - push("java/lang/Class"); - } else if (sort == Type.METHOD) { - push("java/lang/invoke/MethodType"); - } else { - throw new IllegalArgumentException(); - } - } else if (cst instanceof Handle) { - push("java/lang/invoke/MethodHandle"); - } else { - throw new IllegalArgumentException(); - } - labels = null; + pushDescriptor(descriptor); + labels = null; + } + + @Override + public void visitInvokeDynamicInsn( + final String name, + final String descriptor, + final Handle bootstrapMethodHandle, + final Object... bootstrapMethodArguments) { + super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); + if (this.locals == null) { + labels = null; + return; } - - @Override - public void visitIincInsn(final int var, final int increment) { - if (mv != null) { - mv.visitIincInsn(var, increment); - } - execute(Opcodes.IINC, var, null); + pop(descriptor); + pushDescriptor(descriptor); + labels = null; + } + + @Override + public void visitJumpInsn(final int opcode, final Label label) { + super.visitJumpInsn(opcode, label); + execute(opcode, 0, null); + if (opcode == Opcodes.GOTO) { + this.locals = null; + this.stack = null; } + } - @Override - public void visitTableSwitchInsn(final int min, final int max, - final Label dflt, final Label... labels) { - if (mv != null) { - mv.visitTableSwitchInsn(min, max, dflt, labels); - } - execute(Opcodes.TABLESWITCH, 0, null); - this.locals = null; - this.stack = null; + @Override + public void visitLabel(final Label label) { + super.visitLabel(label); + if (labels == null) { + labels = new ArrayList<Label>(3); } - - @Override - public void visitLookupSwitchInsn(final Label dflt, final int[] keys, - final Label[] labels) { - if (mv != null) { - mv.visitLookupSwitchInsn(dflt, keys, labels); - } - execute(Opcodes.LOOKUPSWITCH, 0, null); - this.locals = null; - this.stack = null; + labels.add(label); + } + + @Override + public void visitLdcInsn(final Object value) { + super.visitLdcInsn(value); + if (this.locals == null) { + labels = null; + return; } - - @Override - public void visitMultiANewArrayInsn(final String desc, final int dims) { - if (mv != null) { - mv.visitMultiANewArrayInsn(desc, dims); - } - execute(Opcodes.MULTIANEWARRAY, dims, desc); + if (value instanceof Integer) { + push(Opcodes.INTEGER); + } else if (value instanceof Long) { + push(Opcodes.LONG); + push(Opcodes.TOP); + } else if (value instanceof Float) { + push(Opcodes.FLOAT); + } else if (value instanceof Double) { + push(Opcodes.DOUBLE); + push(Opcodes.TOP); + } else if (value instanceof String) { + push("java/lang/String"); + } else if (value instanceof Type) { + int sort = ((Type) value).getSort(); + if (sort == Type.OBJECT || sort == Type.ARRAY) { + push("java/lang/Class"); + } else if (sort == Type.METHOD) { + push("java/lang/invoke/MethodType"); + } else { + throw new IllegalArgumentException(); + } + } else if (value instanceof Handle) { + push("java/lang/invoke/MethodHandle"); + } else if (value instanceof ConstantDynamic) { + pushDescriptor(((ConstantDynamic) value).getDescriptor()); + } else { + throw new IllegalArgumentException(); } - - @Override - public void visitMaxs(final int maxStack, final int maxLocals) { - if (mv != null) { - this.maxStack = Math.max(this.maxStack, maxStack); - this.maxLocals = Math.max(this.maxLocals, maxLocals); - mv.visitMaxs(this.maxStack, this.maxLocals); - } + labels = null; + } + + @Override + public void visitIincInsn(final int var, final int increment) { + super.visitIincInsn(var, increment); + maxLocals = Math.max(maxLocals, var + 1); + execute(Opcodes.IINC, var, null); + } + + @Override + public void visitTableSwitchInsn( + final int min, final int max, final Label dflt, final Label... labels) { + super.visitTableSwitchInsn(min, max, dflt, labels); + execute(Opcodes.TABLESWITCH, 0, null); + this.locals = null; + this.stack = null; + } + + @Override + public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { + super.visitLookupSwitchInsn(dflt, keys, labels); + execute(Opcodes.LOOKUPSWITCH, 0, null); + this.locals = null; + this.stack = null; + } + + @Override + public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) { + super.visitMultiANewArrayInsn(descriptor, numDimensions); + execute(Opcodes.MULTIANEWARRAY, numDimensions, descriptor); + } + + @Override + public void visitLocalVariable( + final String name, + final String descriptor, + final String signature, + final Label start, + final Label end, + final int index) { + char firstDescriptorChar = descriptor.charAt(0); + maxLocals = + Math.max( + maxLocals, index + (firstDescriptorChar == 'J' || firstDescriptorChar == 'D' ? 2 : 1)); + super.visitLocalVariable(name, descriptor, signature, start, end, index); + } + + @Override + public void visitMaxs(final int maxStack, final int maxLocals) { + if (mv != null) { + this.maxStack = Math.max(this.maxStack, maxStack); + this.maxLocals = Math.max(this.maxLocals, maxLocals); + mv.visitMaxs(this.maxStack, this.maxLocals); } + } - // ------------------------------------------------------------------------ + // ----------------------------------------------------------------------------------------------- - private Object get(final int local) { - maxLocals = Math.max(maxLocals, local + 1); - return local < locals.size() ? locals.get(local) : Opcodes.TOP; - } + private Object get(final int local) { + maxLocals = Math.max(maxLocals, local + 1); + return local < locals.size() ? locals.get(local) : Opcodes.TOP; + } - private void set(final int local, final Object type) { - maxLocals = Math.max(maxLocals, local + 1); - while (local >= locals.size()) { - locals.add(Opcodes.TOP); + private void set(final int local, final Object type) { + maxLocals = Math.max(maxLocals, local + 1); + while (local >= locals.size()) { + locals.add(Opcodes.TOP); + } + locals.set(local, type); + } + + private void push(final Object type) { + stack.add(type); + maxStack = Math.max(maxStack, stack.size()); + } + + private void pushDescriptor(final String descriptor) { + int index = descriptor.charAt(0) == '(' ? descriptor.indexOf(')') + 1 : 0; + switch (descriptor.charAt(index)) { + case 'V': + return; + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + push(Opcodes.INTEGER); + return; + case 'F': + push(Opcodes.FLOAT); + return; + case 'J': + push(Opcodes.LONG); + push(Opcodes.TOP); + return; + case 'D': + push(Opcodes.DOUBLE); + push(Opcodes.TOP); + return; + case '[': + if (index == 0) { + push(descriptor); + } else { + push(descriptor.substring(index, descriptor.length())); } - locals.set(local, type); + break; + case 'L': + if (index == 0) { + push(descriptor.substring(1, descriptor.length() - 1)); + } else { + push(descriptor.substring(index + 1, descriptor.length() - 1)); + } + break; + default: + throw new AssertionError(); } + } - private void push(final Object type) { - stack.add(type); - maxStack = Math.max(maxStack, stack.size()); - } + private Object pop() { + return stack.remove(stack.size() - 1); + } - private void pushDesc(final String desc) { - int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0; - switch (desc.charAt(index)) { - case 'V': - return; - case 'Z': - case 'C': - case 'B': - case 'S': - case 'I': - push(Opcodes.INTEGER); - return; - case 'F': - push(Opcodes.FLOAT); - return; - case 'J': - push(Opcodes.LONG); - push(Opcodes.TOP); - return; - case 'D': - push(Opcodes.DOUBLE); - push(Opcodes.TOP); - return; - case '[': - if (index == 0) { - push(desc); - } else { - push(desc.substring(index, desc.length())); - } - break; - // case 'L': - default: - if (index == 0) { - push(desc.substring(1, desc.length() - 1)); - } else { - push(desc.substring(index + 1, desc.length() - 1)); - } - } + private void pop(final int numSlots) { + int size = stack.size(); + int end = size - numSlots; + for (int i = size - 1; i >= end; --i) { + stack.remove(i); } - - private Object pop() { - return stack.remove(stack.size() - 1); + } + + private void pop(final String descriptor) { + char firstDescriptorChar = descriptor.charAt(0); + if (firstDescriptorChar == '(') { + int numSlots = 0; + Type[] types = Type.getArgumentTypes(descriptor); + for (Type type : types) { + numSlots += type.getSize(); + } + pop(numSlots); + } else if (firstDescriptorChar == 'J' || firstDescriptorChar == 'D') { + pop(2); + } else { + pop(1); } + } - private void pop(final int n) { - int size = stack.size(); - int end = size - n; - for (int i = size - 1; i >= end; --i) { - stack.remove(i); - } + private void execute(final int opcode, final int intArg, final String stringArg) { + if (this.locals == null) { + labels = null; + return; } - - private void pop(final String desc) { - char c = desc.charAt(0); - if (c == '(') { - int n = 0; - Type[] types = Type.getArgumentTypes(desc); - for (int i = 0; i < types.length; ++i) { - n += types[i].getSize(); - } - pop(n); - } else if (c == 'J' || c == 'D') { - pop(2); + Object value1; + Object value2; + Object value3; + Object t4; + switch (opcode) { + case Opcodes.NOP: + case Opcodes.INEG: + case Opcodes.LNEG: + case Opcodes.FNEG: + case Opcodes.DNEG: + case Opcodes.I2B: + case Opcodes.I2C: + case Opcodes.I2S: + case Opcodes.GOTO: + case Opcodes.RETURN: + break; + case Opcodes.ACONST_NULL: + push(Opcodes.NULL); + break; + case Opcodes.ICONST_M1: + case Opcodes.ICONST_0: + case Opcodes.ICONST_1: + case Opcodes.ICONST_2: + case Opcodes.ICONST_3: + case Opcodes.ICONST_4: + case Opcodes.ICONST_5: + case Opcodes.BIPUSH: + case Opcodes.SIPUSH: + push(Opcodes.INTEGER); + break; + case Opcodes.LCONST_0: + case Opcodes.LCONST_1: + push(Opcodes.LONG); + push(Opcodes.TOP); + break; + case Opcodes.FCONST_0: + case Opcodes.FCONST_1: + case Opcodes.FCONST_2: + push(Opcodes.FLOAT); + break; + case Opcodes.DCONST_0: + case Opcodes.DCONST_1: + push(Opcodes.DOUBLE); + push(Opcodes.TOP); + break; + case Opcodes.ILOAD: + case Opcodes.FLOAD: + case Opcodes.ALOAD: + push(get(intArg)); + break; + case Opcodes.LLOAD: + case Opcodes.DLOAD: + push(get(intArg)); + push(Opcodes.TOP); + break; + case Opcodes.LALOAD: + case Opcodes.D2L: + pop(2); + push(Opcodes.LONG); + push(Opcodes.TOP); + break; + case Opcodes.DALOAD: + case Opcodes.L2D: + pop(2); + push(Opcodes.DOUBLE); + push(Opcodes.TOP); + break; + case Opcodes.AALOAD: + pop(1); + value1 = pop(); + if (value1 instanceof String) { + pushDescriptor(((String) value1).substring(1)); + } else if (value1 == Opcodes.NULL) { + push(value1); } else { - pop(1); - } - } - - private void execute(final int opcode, final int iarg, final String sarg) { - if (this.locals == null) { - labels = null; - return; - } - Object t1, t2, t3, t4; - switch (opcode) { - case Opcodes.NOP: - case Opcodes.INEG: - case Opcodes.LNEG: - case Opcodes.FNEG: - case Opcodes.DNEG: - case Opcodes.I2B: - case Opcodes.I2C: - case Opcodes.I2S: - case Opcodes.GOTO: - case Opcodes.RETURN: - break; - case Opcodes.ACONST_NULL: - push(Opcodes.NULL); - break; - case Opcodes.ICONST_M1: - case Opcodes.ICONST_0: - case Opcodes.ICONST_1: - case Opcodes.ICONST_2: - case Opcodes.ICONST_3: - case Opcodes.ICONST_4: - case Opcodes.ICONST_5: - case Opcodes.BIPUSH: - case Opcodes.SIPUSH: - push(Opcodes.INTEGER); - break; - case Opcodes.LCONST_0: - case Opcodes.LCONST_1: - push(Opcodes.LONG); - push(Opcodes.TOP); - break; - case Opcodes.FCONST_0: - case Opcodes.FCONST_1: - case Opcodes.FCONST_2: - push(Opcodes.FLOAT); - break; - case Opcodes.DCONST_0: - case Opcodes.DCONST_1: - push(Opcodes.DOUBLE); - push(Opcodes.TOP); - break; - case Opcodes.ILOAD: - case Opcodes.FLOAD: - case Opcodes.ALOAD: - push(get(iarg)); - break; - case Opcodes.LLOAD: - case Opcodes.DLOAD: - push(get(iarg)); - push(Opcodes.TOP); - break; - case Opcodes.IALOAD: - case Opcodes.BALOAD: - case Opcodes.CALOAD: - case Opcodes.SALOAD: - pop(2); - push(Opcodes.INTEGER); - break; - case Opcodes.LALOAD: - case Opcodes.D2L: - pop(2); - push(Opcodes.LONG); - push(Opcodes.TOP); - break; - case Opcodes.FALOAD: - pop(2); - push(Opcodes.FLOAT); - break; - case Opcodes.DALOAD: - case Opcodes.L2D: - pop(2); - push(Opcodes.DOUBLE); - push(Opcodes.TOP); - break; - case Opcodes.AALOAD: - pop(1); - t1 = pop(); - if (t1 instanceof String) { - pushDesc(((String) t1).substring(1)); - } else if (t1 == Opcodes.NULL) { - push(t1); - } else { - push("java/lang/Object"); - } - break; - case Opcodes.ISTORE: - case Opcodes.FSTORE: - case Opcodes.ASTORE: - t1 = pop(); - set(iarg, t1); - if (iarg > 0) { - t2 = get(iarg - 1); - if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) { - set(iarg - 1, Opcodes.TOP); - } - } - break; - case Opcodes.LSTORE: - case Opcodes.DSTORE: - pop(1); - t1 = pop(); - set(iarg, t1); - set(iarg + 1, Opcodes.TOP); - if (iarg > 0) { - t2 = get(iarg - 1); - if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) { - set(iarg - 1, Opcodes.TOP); - } - } - break; - case Opcodes.IASTORE: - case Opcodes.BASTORE: - case Opcodes.CASTORE: - case Opcodes.SASTORE: - case Opcodes.FASTORE: - case Opcodes.AASTORE: - pop(3); - break; - case Opcodes.LASTORE: - case Opcodes.DASTORE: - pop(4); - break; - case Opcodes.POP: - case Opcodes.IFEQ: - case Opcodes.IFNE: - case Opcodes.IFLT: - case Opcodes.IFGE: - case Opcodes.IFGT: - case Opcodes.IFLE: - case Opcodes.IRETURN: - case Opcodes.FRETURN: - case Opcodes.ARETURN: - case Opcodes.TABLESWITCH: - case Opcodes.LOOKUPSWITCH: - case Opcodes.ATHROW: - case Opcodes.MONITORENTER: - case Opcodes.MONITOREXIT: - case Opcodes.IFNULL: - case Opcodes.IFNONNULL: - pop(1); - break; - case Opcodes.POP2: - case Opcodes.IF_ICMPEQ: - case Opcodes.IF_ICMPNE: - case Opcodes.IF_ICMPLT: - case Opcodes.IF_ICMPGE: - case Opcodes.IF_ICMPGT: - case Opcodes.IF_ICMPLE: - case Opcodes.IF_ACMPEQ: - case Opcodes.IF_ACMPNE: - case Opcodes.LRETURN: - case Opcodes.DRETURN: - pop(2); - break; - case Opcodes.DUP: - t1 = pop(); - push(t1); - push(t1); - break; - case Opcodes.DUP_X1: - t1 = pop(); - t2 = pop(); - push(t1); - push(t2); - push(t1); - break; - case Opcodes.DUP_X2: - t1 = pop(); - t2 = pop(); - t3 = pop(); - push(t1); - push(t3); - push(t2); - push(t1); - break; - case Opcodes.DUP2: - t1 = pop(); - t2 = pop(); - push(t2); - push(t1); - push(t2); - push(t1); - break; - case Opcodes.DUP2_X1: - t1 = pop(); - t2 = pop(); - t3 = pop(); - push(t2); - push(t1); - push(t3); - push(t2); - push(t1); - break; - case Opcodes.DUP2_X2: - t1 = pop(); - t2 = pop(); - t3 = pop(); - t4 = pop(); - push(t2); - push(t1); - push(t4); - push(t3); - push(t2); - push(t1); - break; - case Opcodes.SWAP: - t1 = pop(); - t2 = pop(); - push(t1); - push(t2); - break; - case Opcodes.IADD: - case Opcodes.ISUB: - case Opcodes.IMUL: - case Opcodes.IDIV: - case Opcodes.IREM: - case Opcodes.IAND: - case Opcodes.IOR: - case Opcodes.IXOR: - case Opcodes.ISHL: - case Opcodes.ISHR: - case Opcodes.IUSHR: - case Opcodes.L2I: - case Opcodes.D2I: - case Opcodes.FCMPL: - case Opcodes.FCMPG: - pop(2); - push(Opcodes.INTEGER); - break; - case Opcodes.LADD: - case Opcodes.LSUB: - case Opcodes.LMUL: - case Opcodes.LDIV: - case Opcodes.LREM: - case Opcodes.LAND: - case Opcodes.LOR: - case Opcodes.LXOR: - pop(4); - push(Opcodes.LONG); - push(Opcodes.TOP); - break; - case Opcodes.FADD: - case Opcodes.FSUB: - case Opcodes.FMUL: - case Opcodes.FDIV: - case Opcodes.FREM: - case Opcodes.L2F: - case Opcodes.D2F: - pop(2); - push(Opcodes.FLOAT); - break; - case Opcodes.DADD: - case Opcodes.DSUB: - case Opcodes.DMUL: - case Opcodes.DDIV: - case Opcodes.DREM: - pop(4); - push(Opcodes.DOUBLE); - push(Opcodes.TOP); - break; - case Opcodes.LSHL: - case Opcodes.LSHR: - case Opcodes.LUSHR: - pop(3); - push(Opcodes.LONG); - push(Opcodes.TOP); - break; - case Opcodes.IINC: - set(iarg, Opcodes.INTEGER); - break; - case Opcodes.I2L: - case Opcodes.F2L: - pop(1); - push(Opcodes.LONG); - push(Opcodes.TOP); - break; - case Opcodes.I2F: - pop(1); - push(Opcodes.FLOAT); - break; - case Opcodes.I2D: - case Opcodes.F2D: - pop(1); - push(Opcodes.DOUBLE); - push(Opcodes.TOP); - break; - case Opcodes.F2I: - case Opcodes.ARRAYLENGTH: - case Opcodes.INSTANCEOF: - pop(1); - push(Opcodes.INTEGER); - break; - case Opcodes.LCMP: - case Opcodes.DCMPL: - case Opcodes.DCMPG: - pop(4); - push(Opcodes.INTEGER); - break; - case Opcodes.JSR: - case Opcodes.RET: - throw new RuntimeException("JSR/RET are not supported"); - case Opcodes.GETSTATIC: - pushDesc(sarg); - break; - case Opcodes.PUTSTATIC: - pop(sarg); - break; - case Opcodes.GETFIELD: - pop(1); - pushDesc(sarg); - break; - case Opcodes.PUTFIELD: - pop(sarg); - pop(); - break; - case Opcodes.NEW: - push(labels.get(0)); - break; - case Opcodes.NEWARRAY: - pop(); - switch (iarg) { - case Opcodes.T_BOOLEAN: - pushDesc("[Z"); - break; - case Opcodes.T_CHAR: - pushDesc("[C"); - break; - case Opcodes.T_BYTE: - pushDesc("[B"); - break; - case Opcodes.T_SHORT: - pushDesc("[S"); - break; - case Opcodes.T_INT: - pushDesc("[I"); - break; - case Opcodes.T_FLOAT: - pushDesc("[F"); - break; - case Opcodes.T_DOUBLE: - pushDesc("[D"); - break; - // case Opcodes.T_LONG: - default: - pushDesc("[J"); - break; - } - break; - case Opcodes.ANEWARRAY: - pop(); - pushDesc("[" + Type.getObjectType(sarg)); - break; - case Opcodes.CHECKCAST: - pop(); - pushDesc(Type.getObjectType(sarg).getDescriptor()); - break; - // case Opcodes.MULTIANEWARRAY: - default: - pop(iarg); - pushDesc(sarg); - break; - } - labels = null; + push("java/lang/Object"); + } + break; + case Opcodes.ISTORE: + case Opcodes.FSTORE: + case Opcodes.ASTORE: + value1 = pop(); + set(intArg, value1); + if (intArg > 0) { + value2 = get(intArg - 1); + if (value2 == Opcodes.LONG || value2 == Opcodes.DOUBLE) { + set(intArg - 1, Opcodes.TOP); + } + } + break; + case Opcodes.LSTORE: + case Opcodes.DSTORE: + pop(1); + value1 = pop(); + set(intArg, value1); + set(intArg + 1, Opcodes.TOP); + if (intArg > 0) { + value2 = get(intArg - 1); + if (value2 == Opcodes.LONG || value2 == Opcodes.DOUBLE) { + set(intArg - 1, Opcodes.TOP); + } + } + break; + case Opcodes.IASTORE: + case Opcodes.BASTORE: + case Opcodes.CASTORE: + case Opcodes.SASTORE: + case Opcodes.FASTORE: + case Opcodes.AASTORE: + pop(3); + break; + case Opcodes.LASTORE: + case Opcodes.DASTORE: + pop(4); + break; + case Opcodes.POP: + case Opcodes.IFEQ: + case Opcodes.IFNE: + case Opcodes.IFLT: + case Opcodes.IFGE: + case Opcodes.IFGT: + case Opcodes.IFLE: + case Opcodes.IRETURN: + case Opcodes.FRETURN: + case Opcodes.ARETURN: + case Opcodes.TABLESWITCH: + case Opcodes.LOOKUPSWITCH: + case Opcodes.ATHROW: + case Opcodes.MONITORENTER: + case Opcodes.MONITOREXIT: + case Opcodes.IFNULL: + case Opcodes.IFNONNULL: + pop(1); + break; + case Opcodes.POP2: + case Opcodes.IF_ICMPEQ: + case Opcodes.IF_ICMPNE: + case Opcodes.IF_ICMPLT: + case Opcodes.IF_ICMPGE: + case Opcodes.IF_ICMPGT: + case Opcodes.IF_ICMPLE: + case Opcodes.IF_ACMPEQ: + case Opcodes.IF_ACMPNE: + case Opcodes.LRETURN: + case Opcodes.DRETURN: + pop(2); + break; + case Opcodes.DUP: + value1 = pop(); + push(value1); + push(value1); + break; + case Opcodes.DUP_X1: + value1 = pop(); + value2 = pop(); + push(value1); + push(value2); + push(value1); + break; + case Opcodes.DUP_X2: + value1 = pop(); + value2 = pop(); + value3 = pop(); + push(value1); + push(value3); + push(value2); + push(value1); + break; + case Opcodes.DUP2: + value1 = pop(); + value2 = pop(); + push(value2); + push(value1); + push(value2); + push(value1); + break; + case Opcodes.DUP2_X1: + value1 = pop(); + value2 = pop(); + value3 = pop(); + push(value2); + push(value1); + push(value3); + push(value2); + push(value1); + break; + case Opcodes.DUP2_X2: + value1 = pop(); + value2 = pop(); + value3 = pop(); + t4 = pop(); + push(value2); + push(value1); + push(t4); + push(value3); + push(value2); + push(value1); + break; + case Opcodes.SWAP: + value1 = pop(); + value2 = pop(); + push(value1); + push(value2); + break; + case Opcodes.IALOAD: + case Opcodes.BALOAD: + case Opcodes.CALOAD: + case Opcodes.SALOAD: + case Opcodes.IADD: + case Opcodes.ISUB: + case Opcodes.IMUL: + case Opcodes.IDIV: + case Opcodes.IREM: + case Opcodes.IAND: + case Opcodes.IOR: + case Opcodes.IXOR: + case Opcodes.ISHL: + case Opcodes.ISHR: + case Opcodes.IUSHR: + case Opcodes.L2I: + case Opcodes.D2I: + case Opcodes.FCMPL: + case Opcodes.FCMPG: + pop(2); + push(Opcodes.INTEGER); + break; + case Opcodes.LADD: + case Opcodes.LSUB: + case Opcodes.LMUL: + case Opcodes.LDIV: + case Opcodes.LREM: + case Opcodes.LAND: + case Opcodes.LOR: + case Opcodes.LXOR: + pop(4); + push(Opcodes.LONG); + push(Opcodes.TOP); + break; + case Opcodes.FALOAD: + case Opcodes.FADD: + case Opcodes.FSUB: + case Opcodes.FMUL: + case Opcodes.FDIV: + case Opcodes.FREM: + case Opcodes.L2F: + case Opcodes.D2F: + pop(2); + push(Opcodes.FLOAT); + break; + case Opcodes.DADD: + case Opcodes.DSUB: + case Opcodes.DMUL: + case Opcodes.DDIV: + case Opcodes.DREM: + pop(4); + push(Opcodes.DOUBLE); + push(Opcodes.TOP); + break; + case Opcodes.LSHL: + case Opcodes.LSHR: + case Opcodes.LUSHR: + pop(3); + push(Opcodes.LONG); + push(Opcodes.TOP); + break; + case Opcodes.IINC: + set(intArg, Opcodes.INTEGER); + break; + case Opcodes.I2L: + case Opcodes.F2L: + pop(1); + push(Opcodes.LONG); + push(Opcodes.TOP); + break; + case Opcodes.I2F: + pop(1); + push(Opcodes.FLOAT); + break; + case Opcodes.I2D: + case Opcodes.F2D: + pop(1); + push(Opcodes.DOUBLE); + push(Opcodes.TOP); + break; + case Opcodes.F2I: + case Opcodes.ARRAYLENGTH: + case Opcodes.INSTANCEOF: + pop(1); + push(Opcodes.INTEGER); + break; + case Opcodes.LCMP: + case Opcodes.DCMPL: + case Opcodes.DCMPG: + pop(4); + push(Opcodes.INTEGER); + break; + case Opcodes.JSR: + case Opcodes.RET: + throw new IllegalArgumentException("JSR/RET are not supported"); + case Opcodes.GETSTATIC: + pushDescriptor(stringArg); + break; + case Opcodes.PUTSTATIC: + pop(stringArg); + break; + case Opcodes.GETFIELD: + pop(1); + pushDescriptor(stringArg); + break; + case Opcodes.PUTFIELD: + pop(stringArg); + pop(); + break; + case Opcodes.NEW: + push(labels.get(0)); + break; + case Opcodes.NEWARRAY: + pop(); + switch (intArg) { + case Opcodes.T_BOOLEAN: + pushDescriptor("[Z"); + break; + case Opcodes.T_CHAR: + pushDescriptor("[C"); + break; + case Opcodes.T_BYTE: + pushDescriptor("[B"); + break; + case Opcodes.T_SHORT: + pushDescriptor("[S"); + break; + case Opcodes.T_INT: + pushDescriptor("[I"); + break; + case Opcodes.T_FLOAT: + pushDescriptor("[F"); + break; + case Opcodes.T_DOUBLE: + pushDescriptor("[D"); + break; + case Opcodes.T_LONG: + pushDescriptor("[J"); + break; + default: + throw new IllegalArgumentException("Invalid array type " + intArg); + } + break; + case Opcodes.ANEWARRAY: + pop(); + pushDescriptor("[" + Type.getObjectType(stringArg)); + break; + case Opcodes.CHECKCAST: + pop(); + pushDescriptor(Type.getObjectType(stringArg).getDescriptor()); + break; + case Opcodes.MULTIANEWARRAY: + pop(intArg); + pushDescriptor(stringArg); + break; + default: + throw new IllegalArgumentException("Invalid opcode " + opcode); } + labels = null; + } }
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1c71aec7/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AnnotationRemapper.java ---------------------------------------------------------------------- diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AnnotationRemapper.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AnnotationRemapper.java old mode 100644 new mode 100755 index 74dded8..24a2de5 --- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AnnotationRemapper.java +++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AnnotationRemapper.java @@ -1,32 +1,30 @@ -/*** - * 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.commons; @@ -34,46 +32,72 @@ import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor; import org.apache.tapestry5.internal.plastic.asm.Opcodes; /** - * An {@link AnnotationVisitor} adapter for type remapping. - * + * An {@link AnnotationVisitor} that remaps types with a {@link Remapper}. + * * @author Eugene Kuleshov */ public class AnnotationRemapper extends AnnotationVisitor { - protected final Remapper remapper; + /** The remapper used to remap the types in the visited annotation. */ + protected final Remapper remapper; - public AnnotationRemapper(final AnnotationVisitor av, - final Remapper remapper) { - this(Opcodes.ASM6, av, remapper); - } + /** + * Constructs a new {@link AnnotationRemapper}. <i>Subclasses must not use this constructor</i>. + * Instead, they must use the {@link #AnnotationRemapper(int,AnnotationVisitor,Remapper)} version. + * + * @param annotationVisitor the annotation visitor this remapper must deleted to. + * @param remapper the remapper to use to remap the types in the visited annotation. + */ + public AnnotationRemapper(final AnnotationVisitor annotationVisitor, final Remapper remapper) { + this(Opcodes.ASM7, annotationVisitor, remapper); + } - protected AnnotationRemapper(final int api, final AnnotationVisitor av, - final Remapper remapper) { - super(api, av); - this.remapper = remapper; - } + /** + * Constructs a new {@link AnnotationRemapper}. + * + * @param api the ASM API version supported by this remapper. Must be one of {@link + * org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM4}, {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM5} or {@link + * org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM6}. + * @param annotationVisitor the annotation visitor this remapper must deleted to. + * @param remapper the remapper to use to remap the types in the visited annotation. + */ + protected AnnotationRemapper( + final int api, final AnnotationVisitor annotationVisitor, final Remapper remapper) { + super(api, annotationVisitor); + this.remapper = remapper; + } - @Override - public void visit(String name, Object value) { - av.visit(name, remapper.mapValue(value)); - } + @Override + public void visit(final String name, final Object value) { + super.visit(name, remapper.mapValue(value)); + } - @Override - public void visitEnum(String name, String desc, String value) { - av.visitEnum(name, remapper.mapDesc(desc), value); - } + @Override + public void visitEnum(final String name, final String descriptor, final String value) { + super.visitEnum(name, remapper.mapDesc(descriptor), value); + } - @Override - public AnnotationVisitor visitAnnotation(String name, String desc) { - AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc)); - return v == null ? null : (v == av ? this : new AnnotationRemapper(v, - remapper)); + @Override + public AnnotationVisitor visitAnnotation(final String name, final String descriptor) { + AnnotationVisitor annotationVisitor = super.visitAnnotation(name, remapper.mapDesc(descriptor)); + if (annotationVisitor == null) { + return null; + } else { + return annotationVisitor == av + ? this + : new AnnotationRemapper(api, annotationVisitor, remapper); } + } - @Override - public AnnotationVisitor visitArray(String name) { - AnnotationVisitor v = av.visitArray(name); - return v == null ? null : (v == av ? this : new AnnotationRemapper(v, - remapper)); + @Override + public AnnotationVisitor visitArray(final String name) { + AnnotationVisitor annotationVisitor = super.visitArray(name); + if (annotationVisitor == null) { + return null; + } else { + return annotationVisitor == av + ? this + : new AnnotationRemapper(api, annotationVisitor, remapper); } + } } http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1c71aec7/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ClassRemapper.java ---------------------------------------------------------------------- diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ClassRemapper.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ClassRemapper.java old mode 100644 new mode 100755 index 8090c0d..f837457 --- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ClassRemapper.java +++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ClassRemapper.java @@ -1,37 +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.commons; import java.util.List; - import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor; import org.apache.tapestry5.internal.plastic.asm.Attribute; import org.apache.tapestry5.internal.plastic.asm.ClassVisitor; @@ -42,117 +39,198 @@ import org.apache.tapestry5.internal.plastic.asm.Opcodes; import org.apache.tapestry5.internal.plastic.asm.TypePath; /** - * A {@link ClassVisitor} for type remapping. - * + * A {@link ClassVisitor} that remaps types with a {@link Remapper}. + * * @author Eugene Kuleshov */ public class ClassRemapper extends ClassVisitor { - protected final Remapper remapper; - - protected String className; - - public ClassRemapper(final ClassVisitor cv, final Remapper remapper) { - this(Opcodes.ASM6, cv, remapper); - } - - protected ClassRemapper(final int api, final ClassVisitor cv, - final Remapper remapper) { - super(api, cv); - this.remapper = remapper; - } - - @Override - public void visit(int version, int access, String name, String signature, - String superName, String[] interfaces) { - this.className = name; - super.visit(version, access, remapper.mapType(name), remapper - .mapSignature(signature, false), remapper.mapType(superName), - interfaces == null ? null : remapper.mapTypes(interfaces)); - } - - @Override - public ModuleVisitor visitModule(String name, int flags, String version) { - ModuleVisitor mv = super.visitModule(remapper.mapModuleName(name), flags, version); - return mv == null ? null : createModuleRemapper(mv); - } - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), - visible); - return av == null ? null : createAnnotationRemapper(av); - } - - @Override - public AnnotationVisitor visitTypeAnnotation(int typeRef, - TypePath typePath, String desc, boolean visible) { - AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, - remapper.mapDesc(desc), visible); - return av == null ? null : createAnnotationRemapper(av); - } - - @Override - public void visitAttribute(Attribute attr) { - if (attr instanceof ModuleHashesAttribute) { - ModuleHashesAttribute hashesAttr = new ModuleHashesAttribute(); - List<String> modules = hashesAttr.modules; - for(int i = 0; i < modules.size(); i++) { - modules.set(i, remapper.mapModuleName(modules.get(i))); - } - } - super.visitAttribute(attr); - } - - @Override - public FieldVisitor visitField(int access, String name, String desc, - String signature, Object value) { - FieldVisitor fv = super.visitField(access, - remapper.mapFieldName(className, name, desc), - remapper.mapDesc(desc), remapper.mapSignature(signature, true), - remapper.mapValue(value)); - return fv == null ? null : createFieldRemapper(fv); - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, - String signature, String[] exceptions) { - String newDesc = remapper.mapMethodDesc(desc); - MethodVisitor mv = super.visitMethod(access, remapper.mapMethodName( - className, name, desc), newDesc, remapper.mapSignature( - signature, false), - exceptions == null ? null : remapper.mapTypes(exceptions)); - return mv == null ? null : createMethodRemapper(mv); - } - - @Override - public void visitInnerClass(String name, String outerName, - String innerName, int access) { - // TODO should innerName be changed? - super.visitInnerClass(remapper.mapType(name), outerName == null ? null - : remapper.mapType(outerName), innerName, access); - } - - @Override - public void visitOuterClass(String owner, String name, String desc) { - super.visitOuterClass(remapper.mapType(owner), name == null ? null - : remapper.mapMethodName(owner, name, desc), - desc == null ? null : remapper.mapMethodDesc(desc)); - } - - protected FieldVisitor createFieldRemapper(FieldVisitor fv) { - return new FieldRemapper(fv, remapper); - } - - protected MethodVisitor createMethodRemapper(MethodVisitor mv) { - return new MethodRemapper(mv, remapper); - } - - protected AnnotationVisitor createAnnotationRemapper(AnnotationVisitor av) { - return new AnnotationRemapper(av, remapper); - } - - protected ModuleVisitor createModuleRemapper(ModuleVisitor mv) { - return new ModuleRemapper(mv, remapper); + /** The remapper used to remap the types in the visited class. */ + protected final Remapper remapper; + + /** The internal name of the visited class. */ + protected String className; + + /** + * Constructs a new {@link ClassRemapper}. <i>Subclasses must not use this constructor</i>. + * Instead, they must use the {@link #ClassRemapper(int,ClassVisitor,Remapper)} version. + * + * @param classVisitor the class visitor this remapper must deleted to. + * @param remapper the remapper to use to remap the types in the visited class. + */ + public ClassRemapper(final ClassVisitor classVisitor, final Remapper remapper) { + this(Opcodes.ASM7, classVisitor, remapper); + } + + /** + * Constructs a new {@link ClassRemapper}. + * + * @param api the ASM API version supported by this remapper. 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}. + * @param classVisitor the class visitor this remapper must deleted to. + * @param remapper the remapper to use to remap the types in the visited class. + */ + protected ClassRemapper(final int api, final ClassVisitor classVisitor, final Remapper remapper) { + super(api, classVisitor); + this.remapper = remapper; + } + + @Override + public void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) { + this.className = name; + super.visit( + version, + access, + remapper.mapType(name), + remapper.mapSignature(signature, false), + remapper.mapType(superName), + interfaces == null ? null : remapper.mapTypes(interfaces)); + } + + @Override + public ModuleVisitor visitModule(final String name, final int flags, final String version) { + ModuleVisitor moduleVisitor = super.visitModule(remapper.mapModuleName(name), flags, version); + return moduleVisitor == null ? null : createModuleRemapper(moduleVisitor); + } + + @Override + public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { + AnnotationVisitor annotationVisitor = + super.visitAnnotation(remapper.mapDesc(descriptor), visible); + return annotationVisitor == null ? null : createAnnotationRemapper(annotationVisitor); + } + + @Override + public AnnotationVisitor visitTypeAnnotation( + final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { + AnnotationVisitor annotationVisitor = + super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible); + return annotationVisitor == null ? null : createAnnotationRemapper(annotationVisitor); + } + + @Override + public void visitAttribute(final Attribute attribute) { + if (attribute instanceof ModuleHashesAttribute) { + ModuleHashesAttribute moduleHashesAttribute = (ModuleHashesAttribute) attribute; + List<String> modules = moduleHashesAttribute.modules; + for (int i = 0; i < modules.size(); ++i) { + modules.set(i, remapper.mapModuleName(modules.get(i))); + } } + super.visitAttribute(attribute); + } + + @Override + public FieldVisitor visitField( + final int access, + final String name, + final String descriptor, + final String signature, + final Object value) { + FieldVisitor fieldVisitor = + super.visitField( + access, + remapper.mapFieldName(className, name, descriptor), + remapper.mapDesc(descriptor), + remapper.mapSignature(signature, true), + (value == null) ? null : remapper.mapValue(value)); + return fieldVisitor == null ? null : createFieldRemapper(fieldVisitor); + } + + @Override + public MethodVisitor visitMethod( + final int access, + final String name, + final String descriptor, + final String signature, + final String[] exceptions) { + String remappedDescriptor = remapper.mapMethodDesc(descriptor); + MethodVisitor methodVisitor = + super.visitMethod( + access, + remapper.mapMethodName(className, name, descriptor), + remappedDescriptor, + remapper.mapSignature(signature, false), + exceptions == null ? null : remapper.mapTypes(exceptions)); + return methodVisitor == null ? null : createMethodRemapper(methodVisitor); + } + + @Override + public void visitInnerClass( + final String name, final String outerName, final String innerName, final int access) { + super.visitInnerClass( + remapper.mapType(name), + outerName == null ? null : remapper.mapType(outerName), + innerName == null ? null : remapper.mapInnerClassName(name, outerName, innerName), + access); + } + + @Override + public void visitOuterClass(final String owner, final String name, final String descriptor) { + super.visitOuterClass( + remapper.mapType(owner), + name == null ? null : remapper.mapMethodName(owner, name, descriptor), + descriptor == null ? null : remapper.mapMethodDesc(descriptor)); + } + + @Override + public void visitNestHost(final String nestHost) { + super.visitNestHost(remapper.mapType(nestHost)); + } + + @Override + public void visitNestMember(final String nestMember) { + super.visitNestMember(remapper.mapType(nestMember)); + } + + /** + * Constructs a new remapper for fields. The default implementation of this method returns a new + * {@link FieldRemapper}. + * + * @param fieldVisitor the FieldVisitor the remapper must delegate to. + * @return the newly created remapper. + */ + protected FieldVisitor createFieldRemapper(final FieldVisitor fieldVisitor) { + return new FieldRemapper(api, fieldVisitor, remapper); + } + + /** + * Constructs a new remapper for methods. The default implementation of this method returns a new + * {@link MethodRemapper}. + * + * @param methodVisitor the MethodVisitor the remapper must delegate to. + * @return the newly created remapper. + */ + protected MethodVisitor createMethodRemapper(final MethodVisitor methodVisitor) { + return new MethodRemapper(api, methodVisitor, remapper); + } + + /** + * Constructs a new remapper for annotations. The default implementation of this method returns a + * new {@link AnnotationRemapper}. + * + * @param annotationVisitor the AnnotationVisitor the remapper must delegate to. + * @return the newly created remapper. + */ + protected AnnotationVisitor createAnnotationRemapper(final AnnotationVisitor annotationVisitor) { + return new AnnotationRemapper(api, annotationVisitor, remapper); + } + + /** + * Constructs a new remapper for modules. The default implementation of this method returns a new + * {@link ModuleRemapper}. + * + * @param moduleVisitor the ModuleVisitor the remapper must delegate to. + * @return the newly created remapper. + */ + protected ModuleVisitor createModuleRemapper(final ModuleVisitor moduleVisitor) { + return new ModuleRemapper(api, moduleVisitor, remapper); + } }