From c1f42241366068bd970dd03a19d6222f768f285d Mon Sep 17 00:00:00 2001 From: gil Date: Feb 11 2016 16:30:16 +0000 Subject: update to 2.2.7 --- diff --git a/.gitignore b/.gitignore index fddd236..0dae839 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /mvel2-2.1.6.Final.tar.gz /mvel2-2.2.2.Final.tar.gz /mvel2-2.2.6.Final.tar.gz +/mvel2-2.2.7.Final.tar.gz diff --git a/mvel-2.1.6.Final-java8.patch b/mvel-2.1.6.Final-java8.patch deleted file mode 100644 index e68fd95..0000000 --- a/mvel-2.1.6.Final-java8.patch +++ /dev/null @@ -1,42 +0,0 @@ ---- src/main/java/org/mvel2/util/JITClassLoader.java 2013-06-18 17:03:49.000000000 +0200 -+++ src/main/java/org/mvel2/util/JITClassLoader.java-gil 2014-05-09 09:12:50.590882174 +0200 -@@ -18,38 +18,14 @@ - - package org.mvel2.util; - --import sun.misc.Unsafe; -- - import java.lang.reflect.Field; - - public class JITClassLoader extends ClassLoader implements MVELClassLoader { -- private static boolean sunJVM; -- private static Object sunUnsafe; -- -- static { -- try { -- Field f = Unsafe.class.getDeclaredField("theUnsafe"); -- f.setAccessible(true); -- sunUnsafe = f.get(null); -- sunJVM = true; -- } -- catch (Throwable t) { -- // t.printStackTrace(); -- sunJVM = false; -- } -- } -- -- - public JITClassLoader(ClassLoader classLoader) { - super(classLoader); - } - - public Class defineClassX(String className, byte[] b, int off, int len) { -- if (sunJVM) { -- return ((Unsafe) sunUnsafe).defineClass(className, b, off, len); -- } -- else { -- return super.defineClass(className, b, off, len); -- } -+ return super.defineClass(className, b, off, len); - } - } diff --git a/mvel-2.2.6.Final-tests.patch b/mvel-2.2.6.Final-tests.patch deleted file mode 100644 index 1813856..0000000 --- a/mvel-2.2.6.Final-tests.patch +++ /dev/null @@ -1,76 +0,0 @@ -diff -Nru mvel-mvel2-2.2.6.Final/src/test/java/org/mvel2/tests/classes/ClassTests.java mvel-mvel2-2.2.6.Final.tests/src/test/java/org/mvel2/tests/classes/ClassTests.java ---- mvel-mvel2-2.2.6.Final/src/test/java/org/mvel2/tests/classes/ClassTests.java 2015-08-03 15:38:02.000000000 +0200 -+++ mvel-mvel2-2.2.6.Final.tests/src/test/java/org/mvel2/tests/classes/ClassTests.java 2015-08-25 19:06:38.893242873 +0200 -@@ -14,7 +14,7 @@ - private final String dir = "src/test/java/" + getClass().getPackage().getName().replaceAll("\\.", "/"); - - public void testScript() throws IOException { -- final Object o = MVEL.evalFile(new File(dir + "/demo.mvel"), new HashMap()); -+ //final Object o = MVEL.evalFile(new File(dir + "/demo.mvel"), new HashMap()); - } - - } -diff -Nru mvel-mvel2-2.2.6.Final/src/test/java/org/mvel2/tests/core/CoreConfidenceTests.java mvel-mvel2-2.2.6.Final.tests/src/test/java/org/mvel2/tests/core/CoreConfidenceTests.java ---- mvel-mvel2-2.2.6.Final/src/test/java/org/mvel2/tests/core/CoreConfidenceTests.java 2015-08-03 15:38:02.000000000 +0200 -+++ mvel-mvel2-2.2.6.Final.tests/src/test/java/org/mvel2/tests/core/CoreConfidenceTests.java 2015-08-25 19:06:38.894242826 +0200 -@@ -3389,6 +3389,7 @@ - public void testNestedEnumFromJar() throws ClassNotFoundException, - SecurityException, - NoSuchFieldException { -+/* - String expr = "EventRequest.Status.ACTIVE"; - - // creating a classloader for the jar -@@ -3420,6 +3421,7 @@ - Object result = MVEL.executeExpression(compiled); - - assertNotNull(result); -+*/ - } - - public void testContextObjMethodCall() { -@@ -3432,8 +3434,8 @@ - ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression(str, pctx); - Bar ctx = new Bar(); - ctx.setName("bob"); -- Boolean result = (Boolean) MVEL.executeExpression(stmt, ctx); -- assertTrue(result); -+ //Boolean result = (Boolean) MVEL.executeExpression(stmt, ctx); -+ //assertTrue(result); - } - - public void testMapAccessWithNestedMethodCall() { -@@ -3447,8 +3449,8 @@ - - POJO ctx = new POJO(); - ctx.getMap().put("1", "one"); -- Boolean result = (Boolean) MVEL.executeExpression(stmt, ctx); -- assertTrue(result); -+ //Boolean result = (Boolean) MVEL.executeExpression(stmt, ctx); -+ //assertTrue(result); - } - - public void testMapAccessWithNestedProperty() { -@@ -3462,8 +3464,8 @@ - - POJO ctx = new POJO(); - ctx.getMap().put("1", "one"); -- Boolean result = (Boolean) MVEL.executeExpression(stmt, ctx); -- assertTrue(result); -+ //Boolean result = (Boolean) MVEL.executeExpression(stmt, ctx); -+ //assertTrue(result); - } - - public void testArrays() { -diff -Nru mvel-mvel2-2.2.6.Final/src/test/java/org/mvel2/tests/core/WithTests.java mvel-mvel2-2.2.6.Final.tests/src/test/java/org/mvel2/tests/core/WithTests.java ---- mvel-mvel2-2.2.6.Final/src/test/java/org/mvel2/tests/core/WithTests.java 2015-08-03 15:38:02.000000000 +0200 -+++ mvel-mvel2-2.2.6.Final.tests/src/test/java/org/mvel2/tests/core/WithTests.java 2015-08-25 19:06:38.894242826 +0200 -@@ -352,7 +352,7 @@ - - Serializable s = MVEL.compileExpression(expr); - -- assertEquals("foo", MVEL.executeExpression(s)); -+ //assertEquals("foo", MVEL.executeExpression(s)); - } - - public void testWithAndEnumInPackageImport() { diff --git a/mvel-2.2.6.Final-use-system-asm.patch b/mvel-2.2.6.Final-use-system-asm.patch deleted file mode 100644 index 454eec9..0000000 --- a/mvel-2.2.6.Final-use-system-asm.patch +++ /dev/null @@ -1,44472 +0,0 @@ -diff -Nru mvel-mvel2-2.2.6.Final/pom.xml mvel-mvel2-2.2.6.Final.asm/pom.xml ---- mvel-mvel2-2.2.6.Final/pom.xml 2015-08-03 15:38:02.000000000 +0200 -+++ mvel-mvel2-2.2.6.Final.asm/pom.xml 2015-08-25 19:01:56.533674480 +0200 -@@ -267,6 +267,17 @@ - test - - -+ -+ org.ow2.asm -+ asm -+ 5.0.3 -+ -+ -+ org.ow2.asm -+ asm-util -+ 5.0.3 -+ -+ - - - -diff -Nru mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/AnnotationVisitor.java mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/AnnotationVisitor.java ---- mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/AnnotationVisitor.java 2015-08-03 15:38:02.000000000 +0200 -+++ mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/AnnotationVisitor.java 1970-01-01 01:00:00.000000000 +0100 -@@ -1,169 +0,0 @@ --/*** -- * 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.mvel2.asm; -- --/** -- * A visitor to visit a Java annotation. The methods of this class must be -- * called in the following order: ( visit | visitEnum | -- * visitAnnotation | visitArray )* visitEnd. -- * -- * @author Eric Bruneton -- * @author Eugene Kuleshov -- */ --public abstract class AnnotationVisitor { -- -- /** -- * The ASM API version implemented by this visitor. The value of this field -- * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -- */ -- protected final int api; -- -- /** -- * The annotation visitor to which this visitor must delegate method calls. -- * May be null. -- */ -- protected AnnotationVisitor av; -- -- /** -- * Constructs a new {@link AnnotationVisitor}. -- * -- * @param api -- * the ASM API version implemented by this visitor. Must be one -- * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -- */ -- public AnnotationVisitor(final int api) { -- this(api, null); -- } -- -- /** -- * Constructs a new {@link AnnotationVisitor}. -- * -- * @param api -- * the ASM API version implemented by this visitor. Must be one -- * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -- * @param av -- * the annotation visitor to which this visitor must delegate -- * method calls. May be null. -- */ -- public AnnotationVisitor(final int api, final AnnotationVisitor av) { -- if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { -- throw new IllegalArgumentException(); -- } -- this.api = api; -- this.av = av; -- } -- -- /** -- * Visits a primitive value of the annotation. -- * -- * @param name -- * the value name. -- * @param value -- * the actual value, whose type must be {@link Byte}, -- * {@link Boolean}, {@link Character}, {@link Short}, -- * {@link Integer} , {@link Long}, {@link Float}, {@link Double}, -- * {@link String} or {@link Type} or OBJECT or ARRAY sort. This -- * value can also be an array of byte, boolean, short, char, int, -- * long, float or double values (this is equivalent to using -- * {@link #visitArray visitArray} and visiting each array element -- * in turn, but is more convenient). -- */ -- public void visit(String name, Object value) { -- if (av != null) { -- av.visit(name, value); -- } -- } -- -- /** -- * Visits an enumeration value of the annotation. -- * -- * @param name -- * the value name. -- * @param desc -- * the class descriptor of the enumeration class. -- * @param value -- * the actual enumeration value. -- */ -- public void visitEnum(String name, String desc, String value) { -- if (av != null) { -- av.visitEnum(name, desc, value); -- } -- } -- -- /** -- * Visits a nested annotation value of the annotation. -- * -- * @param name -- * the value name. -- * @param desc -- * the class descriptor of the nested annotation class. -- * @return a visitor to visit the actual nested annotation value, or -- * null if this visitor is not interested in visiting this -- * nested annotation. The nested annotation value must be fully -- * visited before calling other methods on this annotation -- * visitor. -- */ -- public AnnotationVisitor visitAnnotation(String name, String desc) { -- if (av != null) { -- return av.visitAnnotation(name, desc); -- } -- return null; -- } -- -- /** -- * Visits an array value of the annotation. Note that arrays of primitive -- * types (such as byte, boolean, short, char, int, long, float or double) -- * can be passed as value to {@link #visit visit}. This is what -- * {@link ClassReader} does. -- * -- * @param name -- * the value name. -- * @return a visitor to visit the actual array value elements, or -- * null if this visitor is not interested in visiting these -- * values. The 'name' parameters passed to the methods of this -- * visitor are ignored. All the array values must be visited -- * before calling other methods on this annotation visitor. -- */ -- public AnnotationVisitor visitArray(String name) { -- if (av != null) { -- return av.visitArray(name); -- } -- return null; -- } -- -- /** -- * Visits the end of the annotation. -- */ -- public void visitEnd() { -- if (av != null) { -- av.visitEnd(); -- } -- } --} -diff -Nru mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/AnnotationWriter.java mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/AnnotationWriter.java ---- mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/AnnotationWriter.java 2015-08-03 15:38:02.000000000 +0200 -+++ mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/AnnotationWriter.java 1970-01-01 01:00:00.000000000 +0100 -@@ -1,371 +0,0 @@ --/*** -- * 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.mvel2.asm; -- --/** -- * An {@link AnnotationVisitor} that generates annotations in bytecode form. -- * -- * @author Eric Bruneton -- * @author Eugene Kuleshov -- */ --final class AnnotationWriter extends AnnotationVisitor { -- -- /** -- * The class writer to which this annotation must be added. -- */ -- private final ClassWriter cw; -- -- /** -- * The number of values in this annotation. -- */ -- private int size; -- -- /** -- * true if values are named, false otherwise. Annotation -- * writers used for annotation default and annotation arrays use unnamed -- * values. -- */ -- private final boolean named; -- -- /** -- * The annotation values in bytecode form. This byte vector only contains -- * the values themselves, i.e. the number of values must be stored as a -- * unsigned short just before these bytes. -- */ -- private final ByteVector bv; -- -- /** -- * The byte vector to be used to store the number of values of this -- * annotation. See {@link #bv}. -- */ -- private final ByteVector parent; -- -- /** -- * Where the number of values of this annotation must be stored in -- * {@link #parent}. -- */ -- private final int offset; -- -- /** -- * Next annotation writer. This field is used to store annotation lists. -- */ -- AnnotationWriter next; -- -- /** -- * Previous annotation writer. This field is used to store annotation lists. -- */ -- AnnotationWriter prev; -- -- // ------------------------------------------------------------------------ -- // Constructor -- // ------------------------------------------------------------------------ -- -- /** -- * Constructs a new {@link AnnotationWriter}. -- * -- * @param cw -- * the class writer to which this annotation must be added. -- * @param named -- * true if values are named, false otherwise. -- * @param bv -- * where the annotation values must be stored. -- * @param parent -- * where the number of annotation values must be stored. -- * @param offset -- * where in parent the number of annotation values must -- * be stored. -- */ -- AnnotationWriter(final ClassWriter cw, final boolean named, -- final ByteVector bv, final ByteVector parent, final int offset) { -- super(Opcodes.ASM5); -- this.cw = cw; -- this.named = named; -- this.bv = bv; -- this.parent = parent; -- this.offset = offset; -- } -- -- // ------------------------------------------------------------------------ -- // Implementation of the AnnotationVisitor abstract class -- // ------------------------------------------------------------------------ -- -- @Override -- public void visit(final String name, final Object value) { -- ++size; -- if (named) { -- bv.putShort(cw.newUTF8(name)); -- } -- if (value instanceof String) { -- bv.put12('s', cw.newUTF8((String) value)); -- } else if (value instanceof Byte) { -- bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index); -- } else if (value instanceof Boolean) { -- int v = ((Boolean) value).booleanValue() ? 1 : 0; -- bv.put12('Z', cw.newInteger(v).index); -- } else if (value instanceof Character) { -- bv.put12('C', cw.newInteger(((Character) value).charValue()).index); -- } else if (value instanceof Short) { -- bv.put12('S', cw.newInteger(((Short) value).shortValue()).index); -- } else if (value instanceof Type) { -- bv.put12('c', cw.newUTF8(((Type) value).getDescriptor())); -- } else if (value instanceof byte[]) { -- byte[] v = (byte[]) value; -- bv.put12('[', v.length); -- for (int i = 0; i < v.length; i++) { -- bv.put12('B', cw.newInteger(v[i]).index); -- } -- } else if (value instanceof boolean[]) { -- boolean[] v = (boolean[]) value; -- bv.put12('[', v.length); -- for (int i = 0; i < v.length; i++) { -- bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index); -- } -- } else if (value instanceof short[]) { -- short[] v = (short[]) value; -- bv.put12('[', v.length); -- for (int i = 0; i < v.length; i++) { -- bv.put12('S', cw.newInteger(v[i]).index); -- } -- } else if (value instanceof char[]) { -- char[] v = (char[]) value; -- bv.put12('[', v.length); -- for (int i = 0; i < v.length; i++) { -- bv.put12('C', cw.newInteger(v[i]).index); -- } -- } else if (value instanceof int[]) { -- int[] v = (int[]) value; -- bv.put12('[', v.length); -- for (int i = 0; i < v.length; i++) { -- bv.put12('I', cw.newInteger(v[i]).index); -- } -- } else if (value instanceof long[]) { -- long[] v = (long[]) value; -- bv.put12('[', v.length); -- for (int i = 0; i < v.length; i++) { -- bv.put12('J', cw.newLong(v[i]).index); -- } -- } else if (value instanceof float[]) { -- float[] v = (float[]) value; -- bv.put12('[', v.length); -- for (int i = 0; i < v.length; i++) { -- bv.put12('F', cw.newFloat(v[i]).index); -- } -- } else if (value instanceof double[]) { -- double[] v = (double[]) value; -- bv.put12('[', v.length); -- for (int i = 0; i < v.length; i++) { -- bv.put12('D', cw.newDouble(v[i]).index); -- } -- } else { -- Item i = cw.newConstItem(value); -- bv.put12(".s.IFJDCS".charAt(i.type), i.index); -- } -- } -- -- @Override -- public void visitEnum(final String name, final String desc, -- final String value) { -- ++size; -- if (named) { -- bv.putShort(cw.newUTF8(name)); -- } -- bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value)); -- } -- -- @Override -- public AnnotationVisitor visitAnnotation(final String name, -- final String desc) { -- ++size; -- if (named) { -- bv.putShort(cw.newUTF8(name)); -- } -- // write tag and type, and reserve space for values count -- bv.put12('@', cw.newUTF8(desc)).putShort(0); -- return new AnnotationWriter(cw, true, bv, bv, bv.length - 2); -- } -- -- @Override -- public AnnotationVisitor visitArray(final String name) { -- ++size; -- if (named) { -- bv.putShort(cw.newUTF8(name)); -- } -- // write tag, and reserve space for array size -- bv.put12('[', 0); -- return new AnnotationWriter(cw, false, bv, bv, bv.length - 2); -- } -- -- @Override -- public void visitEnd() { -- if (parent != null) { -- byte[] data = parent.data; -- data[offset] = (byte) (size >>> 8); -- data[offset + 1] = (byte) size; -- } -- } -- -- // ------------------------------------------------------------------------ -- // Utility methods -- // ------------------------------------------------------------------------ -- -- /** -- * Returns the size of this annotation writer list. -- * -- * @return the size of this annotation writer list. -- */ -- int getSize() { -- int size = 0; -- AnnotationWriter aw = this; -- while (aw != null) { -- size += aw.bv.length; -- aw = aw.next; -- } -- return size; -- } -- -- /** -- * Puts the annotations of this annotation writer list into the given byte -- * vector. -- * -- * @param out -- * where the annotations must be put. -- */ -- void put(final ByteVector out) { -- int n = 0; -- int size = 2; -- AnnotationWriter aw = this; -- AnnotationWriter last = null; -- while (aw != null) { -- ++n; -- size += aw.bv.length; -- aw.visitEnd(); // in case user forgot to call visitEnd -- aw.prev = last; -- last = aw; -- aw = aw.next; -- } -- out.putInt(size); -- out.putShort(n); -- aw = last; -- while (aw != null) { -- out.putByteArray(aw.bv.data, 0, aw.bv.length); -- aw = aw.prev; -- } -- } -- -- /** -- * Puts the given annotation lists into the given byte vector. -- * -- * @param panns -- * an array of annotation writer lists. -- * @param off -- * index of the first annotation to be written. -- * @param out -- * where the annotations must be put. -- */ -- static void put(final AnnotationWriter[] panns, final int off, -- final ByteVector out) { -- int size = 1 + 2 * (panns.length - off); -- for (int i = off; i < panns.length; ++i) { -- size += panns[i] == null ? 0 : panns[i].getSize(); -- } -- out.putInt(size).putByte(panns.length - off); -- for (int i = off; i < panns.length; ++i) { -- AnnotationWriter aw = panns[i]; -- AnnotationWriter last = null; -- int n = 0; -- while (aw != null) { -- ++n; -- aw.visitEnd(); // in case user forgot to call visitEnd -- aw.prev = last; -- last = aw; -- aw = aw.next; -- } -- out.putShort(n); -- aw = last; -- while (aw != null) { -- out.putByteArray(aw.bv.data, 0, aw.bv.length); -- aw = aw.prev; -- } -- } -- } -- -- /** -- * Puts the given type reference and type path into the given bytevector. -- * LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported. -- * -- * @param typeRef -- * a reference to the annotated type. See {@link TypeReference}. -- * @param typePath -- * the path to the annotated type argument, wildcard bound, array -- * element type, or static inner type within 'typeRef'. May be -- * null if the annotation targets 'typeRef' as a whole. -- * @param out -- * where the type reference and type path must be put. -- */ -- static void putTarget(int typeRef, TypePath typePath, ByteVector out) { -- switch (typeRef >>> 24) { -- case 0x00: // CLASS_TYPE_PARAMETER -- case 0x01: // METHOD_TYPE_PARAMETER -- case 0x16: // METHOD_FORMAL_PARAMETER -- out.putShort(typeRef >>> 16); -- break; -- case 0x13: // FIELD -- case 0x14: // METHOD_RETURN -- case 0x15: // METHOD_RECEIVER -- out.putByte(typeRef >>> 24); -- break; -- case 0x47: // CAST -- case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -- case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT -- case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -- case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT -- out.putInt(typeRef); -- break; -- // case 0x10: // CLASS_EXTENDS -- // case 0x11: // CLASS_TYPE_PARAMETER_BOUND -- // case 0x12: // METHOD_TYPE_PARAMETER_BOUND -- // case 0x17: // THROWS -- // case 0x42: // EXCEPTION_PARAMETER -- // case 0x43: // INSTANCEOF -- // case 0x44: // NEW -- // case 0x45: // CONSTRUCTOR_REFERENCE -- // case 0x46: // METHOD_REFERENCE -- default: -- out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8); -- break; -- } -- if (typePath == null) { -- out.putByte(0); -- } else { -- int length = typePath.b[typePath.offset] * 2 + 1; -- out.putByteArray(typePath.b, typePath.offset, length); -- } -- } --} -diff -Nru mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/Attribute.java mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/Attribute.java ---- mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/Attribute.java 2015-08-03 15:38:02.000000000 +0200 -+++ mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/Attribute.java 1970-01-01 01:00:00.000000000 +0100 -@@ -1,255 +0,0 @@ --/*** -- * 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.mvel2.asm; -- --/** -- * A non standard class, field, method or code attribute. -- * -- * @author Eric Bruneton -- * @author Eugene Kuleshov -- */ --public class Attribute { -- -- /** -- * The type of this attribute. -- */ -- public final String type; -- -- /** -- * The raw value of this attribute, used only for unknown attributes. -- */ -- byte[] value; -- -- /** -- * The next attribute in this attribute list. May be null. -- */ -- Attribute next; -- -- /** -- * Constructs a new empty attribute. -- * -- * @param type -- * the type of the attribute. -- */ -- protected Attribute(final String type) { -- this.type = type; -- } -- -- /** -- * Returns true if this type of attribute is unknown. The default -- * implementation of this method always returns true. -- * -- * @return true if this type of attribute is unknown. -- */ -- public boolean isUnknown() { -- return true; -- } -- -- /** -- * Returns true if this type of attribute is a code attribute. -- * -- * @return true if this type of attribute is a code attribute. -- */ -- public boolean isCodeAttribute() { -- return false; -- } -- -- /** -- * Returns the labels corresponding to this attribute. -- * -- * @return the labels corresponding to this attribute, or null if -- * this attribute is not a code attribute that contains labels. -- */ -- protected Label[] getLabels() { -- return null; -- } -- -- /** -- * Reads a {@link #type type} attribute. This method must return a -- * new {@link Attribute} object, of type {@link #type type}, -- * corresponding to the len bytes starting at the given offset, in -- * the given class reader. -- * -- * @param cr -- * the class that contains the attribute to be read. -- * @param off -- * index of the first byte of the attribute's content in -- * {@link ClassReader#b cr.b}. The 6 attribute header bytes, -- * containing the type and the length of the attribute, are not -- * taken into account here. -- * @param len -- * the length of the attribute's content. -- * @param buf -- * buffer to be used to call {@link ClassReader#readUTF8 -- * readUTF8}, {@link ClassReader#readClass(int,char[]) readClass} -- * or {@link ClassReader#readConst readConst}. -- * @param codeOff -- * index of the first byte of code's attribute content in -- * {@link ClassReader#b cr.b}, or -1 if the attribute to be read -- * is not a code attribute. The 6 attribute header bytes, -- * containing the type and the length of the attribute, are not -- * taken into account here. -- * @param labels -- * the labels of the method's code, or null if the -- * attribute to be read is not a code attribute. -- * @return a new {@link Attribute} object corresponding to the given -- * bytes. -- */ -- protected Attribute read(final ClassReader cr, final int off, -- final int len, final char[] buf, final int codeOff, -- final Label[] labels) { -- Attribute attr = new Attribute(type); -- attr.value = new byte[len]; -- System.arraycopy(cr.b, off, attr.value, 0, len); -- return attr; -- } -- -- /** -- * Returns the byte array form of this attribute. -- * -- * @param cw -- * the class to which this attribute must be added. This -- * parameter can be used to add to the constant pool of this -- * class the items that corresponds to this attribute. -- * @param code -- * the bytecode of the method corresponding to this code -- * attribute, or null if this attribute is not a code -- * attributes. -- * @param len -- * the length of the bytecode of the method corresponding to this -- * code attribute, or null if this attribute is not a -- * code attribute. -- * @param maxStack -- * the maximum stack size of the method corresponding to this -- * code attribute, or -1 if this attribute is not a code -- * attribute. -- * @param maxLocals -- * the maximum number of local variables of the method -- * corresponding to this code attribute, or -1 if this attribute -- * is not a code attribute. -- * @return the byte array form of this attribute. -- */ -- protected ByteVector write(final ClassWriter cw, final byte[] code, -- final int len, final int maxStack, final int maxLocals) { -- ByteVector v = new ByteVector(); -- v.data = value; -- v.length = value.length; -- return v; -- } -- -- /** -- * Returns the length of the attribute list that begins with this attribute. -- * -- * @return the length of the attribute list that begins with this attribute. -- */ -- final int getCount() { -- int count = 0; -- Attribute attr = this; -- while (attr != null) { -- count += 1; -- attr = attr.next; -- } -- return count; -- } -- -- /** -- * Returns the size of all the attributes in this attribute list. -- * -- * @param cw -- * the class writer to be used to convert the attributes into -- * byte arrays, with the {@link #write write} method. -- * @param code -- * the bytecode of the method corresponding to these code -- * attributes, or null if these attributes are not code -- * attributes. -- * @param len -- * the length of the bytecode of the method corresponding to -- * these code attributes, or null if these attributes -- * are not code attributes. -- * @param maxStack -- * the maximum stack size of the method corresponding to these -- * code attributes, or -1 if these attributes are not code -- * attributes. -- * @param maxLocals -- * the maximum number of local variables of the method -- * corresponding to these code attributes, or -1 if these -- * attributes are not code attributes. -- * @return the size of all the attributes in this attribute list. This size -- * includes the size of the attribute headers. -- */ -- final int getSize(final ClassWriter cw, final byte[] code, final int len, -- final int maxStack, final int maxLocals) { -- Attribute attr = this; -- int size = 0; -- while (attr != null) { -- cw.newUTF8(attr.type); -- size += attr.write(cw, code, len, maxStack, maxLocals).length + 6; -- attr = attr.next; -- } -- return size; -- } -- -- /** -- * Writes all the attributes of this attribute list in the given byte -- * vector. -- * -- * @param cw -- * the class writer to be used to convert the attributes into -- * byte arrays, with the {@link #write write} method. -- * @param code -- * the bytecode of the method corresponding to these code -- * attributes, or null if these attributes are not code -- * attributes. -- * @param len -- * the length of the bytecode of the method corresponding to -- * these code attributes, or null if these attributes -- * are not code attributes. -- * @param maxStack -- * the maximum stack size of the method corresponding to these -- * code attributes, or -1 if these attributes are not code -- * attributes. -- * @param maxLocals -- * the maximum number of local variables of the method -- * corresponding to these code attributes, or -1 if these -- * attributes are not code attributes. -- * @param out -- * where the attributes must be written. -- */ -- final void put(final ClassWriter cw, final byte[] code, final int len, -- final int maxStack, final int maxLocals, final ByteVector out) { -- Attribute attr = this; -- while (attr != null) { -- ByteVector b = attr.write(cw, code, len, maxStack, maxLocals); -- out.putShort(cw.newUTF8(attr.type)).putInt(b.length); -- out.putByteArray(b.data, 0, b.length); -- attr = attr.next; -- } -- } --} -diff -Nru mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/attrs/package.html mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/attrs/package.html ---- mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/attrs/package.html 2015-08-03 15:38:02.000000000 +0200 -+++ mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/attrs/package.html 1970-01-01 01:00:00.000000000 +0100 -@@ -1,49 +0,0 @@ -- -- -- --Provides an implementation for optional class, field and method attributes. -- --

-- -- By default ASM strips optional attributes, in order to keep them in -- the bytecode that is being readed you should pass an array of required attribute -- instances to {@link org.mvel2.asm.ClassReader#accept(org.mvel2.asm.ClassVisitor, -- org.mvel2.asm.Attribute[], boolean) ClassReader.accept()} method. -- In order to add custom attributes to the manually constructed bytecode concrete -- subclasses of the {@link org.mvel2.asm.Attribute Attribute} can be passed to -- the visitAttribute methods of the -- {@link org.mvel2.asm.ClassVisitor ClassVisitor}, -- {@link org.mvel2.asm.FieldVisitor FieldVisitor} and -- {@link org.mvel2.asm.MethodVisitor MethodVisitor} interfaces. -- -- @since ASM 1.4.1 -- -- -diff -Nru mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/ByteVector.java mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/ByteVector.java ---- mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/ByteVector.java 2015-08-03 15:38:02.000000000 +0200 -+++ mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/ByteVector.java 1970-01-01 01:00:00.000000000 +0100 -@@ -1,339 +0,0 @@ --/*** -- * 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.mvel2.asm; -- --/** -- * A dynamically extensible vector of bytes. This class is roughly equivalent to -- * a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient. -- * -- * @author Eric Bruneton -- */ --public class ByteVector { -- -- /** -- * The content of this vector. -- */ -- byte[] data; -- -- /** -- * Actual number of bytes in this vector. -- */ -- int length; -- -- /** -- * Constructs a new {@link ByteVector ByteVector} with a default initial -- * size. -- */ -- public ByteVector() { -- data = new byte[64]; -- } -- -- /** -- * Constructs a new {@link ByteVector ByteVector} with the given initial -- * size. -- * -- * @param initialSize -- * the initial size of the byte vector to be constructed. -- */ -- public ByteVector(final int initialSize) { -- data = new byte[initialSize]; -- } -- -- /** -- * Puts a byte into this byte vector. The byte vector is automatically -- * enlarged if necessary. -- * -- * @param b -- * a byte. -- * @return this byte vector. -- */ -- public ByteVector putByte(final int b) { -- int length = this.length; -- if (length + 1 > data.length) { -- enlarge(1); -- } -- data[length++] = (byte) b; -- this.length = length; -- return this; -- } -- -- /** -- * Puts two bytes into this byte vector. The byte vector is automatically -- * enlarged if necessary. -- * -- * @param b1 -- * a byte. -- * @param b2 -- * another byte. -- * @return this byte vector. -- */ -- ByteVector put11(final int b1, final int b2) { -- int length = this.length; -- if (length + 2 > data.length) { -- enlarge(2); -- } -- byte[] data = this.data; -- data[length++] = (byte) b1; -- data[length++] = (byte) b2; -- this.length = length; -- return this; -- } -- -- /** -- * Puts a short into this byte vector. The byte vector is automatically -- * enlarged if necessary. -- * -- * @param s -- * a short. -- * @return this byte vector. -- */ -- public ByteVector putShort(final int s) { -- int length = this.length; -- if (length + 2 > data.length) { -- enlarge(2); -- } -- byte[] data = this.data; -- data[length++] = (byte) (s >>> 8); -- data[length++] = (byte) s; -- this.length = length; -- return this; -- } -- -- /** -- * Puts a byte and a short into this byte vector. The byte vector is -- * automatically enlarged if necessary. -- * -- * @param b -- * a byte. -- * @param s -- * a short. -- * @return this byte vector. -- */ -- ByteVector put12(final int b, final int s) { -- int length = this.length; -- if (length + 3 > data.length) { -- enlarge(3); -- } -- byte[] data = this.data; -- data[length++] = (byte) b; -- data[length++] = (byte) (s >>> 8); -- data[length++] = (byte) s; -- this.length = length; -- return this; -- } -- -- /** -- * Puts an int into this byte vector. The byte vector is automatically -- * enlarged if necessary. -- * -- * @param i -- * an int. -- * @return this byte vector. -- */ -- public ByteVector putInt(final int i) { -- int length = this.length; -- if (length + 4 > data.length) { -- enlarge(4); -- } -- byte[] data = this.data; -- data[length++] = (byte) (i >>> 24); -- data[length++] = (byte) (i >>> 16); -- data[length++] = (byte) (i >>> 8); -- data[length++] = (byte) i; -- this.length = length; -- return this; -- } -- -- /** -- * Puts a long into this byte vector. The byte vector is automatically -- * enlarged if necessary. -- * -- * @param l -- * a long. -- * @return this byte vector. -- */ -- public ByteVector putLong(final long l) { -- int length = this.length; -- if (length + 8 > data.length) { -- enlarge(8); -- } -- byte[] data = this.data; -- int i = (int) (l >>> 32); -- data[length++] = (byte) (i >>> 24); -- data[length++] = (byte) (i >>> 16); -- data[length++] = (byte) (i >>> 8); -- data[length++] = (byte) i; -- i = (int) l; -- data[length++] = (byte) (i >>> 24); -- data[length++] = (byte) (i >>> 16); -- data[length++] = (byte) (i >>> 8); -- data[length++] = (byte) i; -- this.length = length; -- return this; -- } -- -- /** -- * Puts an UTF8 string into this byte vector. The byte vector is -- * automatically enlarged if necessary. -- * -- * @param s -- * a String whose UTF8 encoded length must be less than 65536. -- * @return this byte vector. -- */ -- public ByteVector putUTF8(final String s) { -- int charLength = s.length(); -- if (charLength > 65535) { -- throw new IllegalArgumentException(); -- } -- int len = length; -- if (len + 2 + charLength > data.length) { -- enlarge(2 + charLength); -- } -- byte[] data = this.data; -- // optimistic algorithm: instead of computing the byte length and then -- // serializing the string (which requires two loops), we assume the byte -- // length is equal to char length (which is the most frequent case), and -- // we start serializing the string right away. During the serialization, -- // if we find that this assumption is wrong, we continue with the -- // general method. -- data[len++] = (byte) (charLength >>> 8); -- data[len++] = (byte) charLength; -- for (int i = 0; i < charLength; ++i) { -- char c = s.charAt(i); -- if (c >= '\001' && c <= '\177') { -- data[len++] = (byte) c; -- } else { -- length = len; -- return encodeUTF8(s, i, 65535); -- } -- } -- length = len; -- return this; -- } -- -- /** -- * Puts an UTF8 string into this byte vector. The byte vector is -- * automatically enlarged if necessary. The string length is encoded in two -- * bytes before the encoded characters, if there is space for that (i.e. if -- * this.length - i - 2 >= 0). -- * -- * @param s -- * the String to encode. -- * @param i -- * the index of the first character to encode. The previous -- * characters are supposed to have already been encoded, using -- * only one byte per character. -- * @param maxByteLength -- * the maximum byte length of the encoded string, including the -- * already encoded characters. -- * @return this byte vector. -- */ -- ByteVector encodeUTF8(final String s, int i, int maxByteLength) { -- int charLength = s.length(); -- int byteLength = i; -- char c; -- for (int j = i; j < charLength; ++j) { -- c = s.charAt(j); -- if (c >= '\001' && c <= '\177') { -- byteLength++; -- } else if (c > '\u07FF') { -- byteLength += 3; -- } else { -- byteLength += 2; -- } -- } -- if (byteLength > maxByteLength) { -- throw new IllegalArgumentException(); -- } -- int start = length - i - 2; -- if (start >= 0) { -- data[start] = (byte) (byteLength >>> 8); -- data[start + 1] = (byte) byteLength; -- } -- if (length + byteLength - i > data.length) { -- enlarge(byteLength - i); -- } -- int len = length; -- for (int j = i; j < charLength; ++j) { -- c = s.charAt(j); -- if (c >= '\001' && c <= '\177') { -- data[len++] = (byte) c; -- } else if (c > '\u07FF') { -- data[len++] = (byte) (0xE0 | c >> 12 & 0xF); -- data[len++] = (byte) (0x80 | c >> 6 & 0x3F); -- data[len++] = (byte) (0x80 | c & 0x3F); -- } else { -- data[len++] = (byte) (0xC0 | c >> 6 & 0x1F); -- data[len++] = (byte) (0x80 | c & 0x3F); -- } -- } -- length = len; -- return this; -- } -- -- /** -- * Puts an array of bytes into this byte vector. The byte vector is -- * automatically enlarged if necessary. -- * -- * @param b -- * an array of bytes. May be null to put len -- * null bytes into this byte vector. -- * @param off -- * index of the fist byte of b that must be copied. -- * @param len -- * number of bytes of b that must be copied. -- * @return this byte vector. -- */ -- public ByteVector putByteArray(final byte[] b, final int off, final int len) { -- if (length + len > data.length) { -- enlarge(len); -- } -- if (b != null) { -- System.arraycopy(b, off, data, length, len); -- } -- length += len; -- return this; -- } -- -- /** -- * Enlarge this byte vector so that it can receive n more bytes. -- * -- * @param size -- * number of additional bytes that this byte vector should be -- * able to receive. -- */ -- private void enlarge(final int size) { -- int length1 = 2 * data.length; -- int length2 = length + size; -- byte[] newData = new byte[length1 > length2 ? length1 : length2]; -- System.arraycopy(data, 0, newData, 0, length); -- data = newData; -- } --} -diff -Nru mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/ClassReader.java mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/ClassReader.java ---- mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/ClassReader.java 2015-08-03 15:38:02.000000000 +0200 -+++ mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/ClassReader.java 1970-01-01 01:00:00.000000000 +0100 -@@ -1,2496 +0,0 @@ --/*** -- * 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.mvel2.asm; -- --import java.io.IOException; --import java.io.InputStream; -- --/** -- * A Java class parser to make a {@link ClassVisitor} visit an existing class. -- * This class parses a byte array conforming to the Java class file format and -- * calls the appropriate visit methods of a given class visitor for each field, -- * method and bytecode instruction encountered. -- * -- * @author Eric Bruneton -- * @author Eugene Kuleshov -- */ --public class ClassReader { -- -- /** -- * True to enable signatures support. -- */ -- static final boolean SIGNATURES = true; -- -- /** -- * True to enable annotations support. -- */ -- static final boolean ANNOTATIONS = true; -- -- /** -- * True to enable stack map frames support. -- */ -- static final boolean FRAMES = true; -- -- /** -- * True to enable bytecode writing support. -- */ -- static final boolean WRITER = true; -- -- /** -- * True to enable JSR_W and GOTO_W support. -- */ -- static final boolean RESIZE = true; -- -- /** -- * Flag to skip method code. If this class is set CODE -- * attribute won't be visited. This can be used, for example, to retrieve -- * annotations for methods and method parameters. -- */ -- public static final int SKIP_CODE = 1; -- -- /** -- * Flag to skip the debug information in the class. If this flag is set the -- * debug information of the class is not visited, i.e. the -- * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and -- * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be -- * called. -- */ -- public static final int SKIP_DEBUG = 2; -- -- /** -- * Flag to skip the stack map frames in the class. If this flag is set the -- * stack map frames of the class is not visited, i.e. the -- * {@link MethodVisitor#visitFrame visitFrame} method will not be called. -- * This flag is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is -- * used: it avoids visiting frames that will be ignored and recomputed from -- * scratch in the class writer. -- */ -- public static final int SKIP_FRAMES = 4; -- -- /** -- * Flag to expand the stack map frames. By default stack map frames are -- * visited in their original format (i.e. "expanded" for classes whose -- * version is less than V1_6, and "compressed" for the other classes). If -- * this flag is set, stack map frames are always visited in expanded format -- * (this option adds a decompression/recompression step in ClassReader and -- * ClassWriter which degrades performances quite a lot). -- */ -- public static final int EXPAND_FRAMES = 8; -- -- /** -- * The class to be parsed. The content of this array must not be -- * modified. This field is intended for {@link Attribute} sub classes, and -- * is normally not needed by class generators or adapters. -- */ -- public final byte[] b; -- -- /** -- * The start index of each constant pool item in {@link #b b}, plus one. The -- * one byte offset skips the constant pool item tag that indicates its type. -- */ -- private final int[] items; -- -- /** -- * The String objects corresponding to the CONSTANT_Utf8 items. This cache -- * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item, -- * which GREATLY improves performances (by a factor 2 to 3). This caching -- * strategy could be extended to all constant pool items, but its benefit -- * would not be so great for these items (because they are much less -- * expensive to parse than CONSTANT_Utf8 items). -- */ -- private final String[] strings; -- -- /** -- * Maximum length of the strings contained in the constant pool of the -- * class. -- */ -- private final int maxStringLength; -- -- /** -- * Start index of the class header information (access, name...) in -- * {@link #b b}. -- */ -- public final int header; -- -- // ------------------------------------------------------------------------ -- // Constructors -- // ------------------------------------------------------------------------ -- -- /** -- * Constructs a new {@link ClassReader} object. -- * -- * @param b -- * the bytecode of the class to be read. -- */ -- public ClassReader(final byte[] b) { -- this(b, 0, b.length); -- } -- -- /** -- * Constructs a new {@link ClassReader} object. -- * -- * @param b -- * the bytecode of the class to be read. -- * @param off -- * the start offset of the class data. -- * @param len -- * the length of the class data. -- */ -- public ClassReader(final byte[] b, final int off, final int len) { -- this.b = b; -- // checks the class version -- if (readShort(off + 6) > Opcodes.V1_8) { -- throw new IllegalArgumentException(); -- } -- // parses the constant pool -- items = new int[readUnsignedShort(off + 8)]; -- int n = items.length; -- strings = new String[n]; -- int max = 0; -- int index = off + 10; -- for (int i = 1; i < n; ++i) { -- items[i] = index + 1; -- int size; -- switch (b[index]) { -- case ClassWriter.FIELD: -- case ClassWriter.METH: -- case ClassWriter.IMETH: -- case ClassWriter.INT: -- case ClassWriter.FLOAT: -- case ClassWriter.NAME_TYPE: -- case ClassWriter.INDY: -- size = 5; -- break; -- case ClassWriter.LONG: -- case ClassWriter.DOUBLE: -- size = 9; -- ++i; -- break; -- case ClassWriter.UTF8: -- size = 3 + readUnsignedShort(index + 1); -- if (size > max) { -- max = size; -- } -- break; -- case ClassWriter.HANDLE: -- size = 4; -- break; -- // case ClassWriter.CLASS: -- // case ClassWriter.STR: -- // case ClassWriter.MTYPE -- default: -- size = 3; -- break; -- } -- index += size; -- } -- maxStringLength = max; -- // the class header information starts just after the constant pool -- header = index; -- } -- -- /** -- * Returns the class's access flags (see {@link Opcodes}). This value may -- * not reflect Deprecated and Synthetic flags when bytecode is before 1.5 -- * and those flags are represented by attributes. -- * -- * @return the class access flags -- * -- * @see ClassVisitor#visit(int, int, String, String, String, String[]) -- */ -- public int getAccess() { -- return readUnsignedShort(header); -- } -- -- /** -- * Returns the internal name of the class (see -- * {@link Type#getInternalName() getInternalName}). -- * -- * @return the internal class name -- * -- * @see ClassVisitor#visit(int, int, String, String, String, String[]) -- */ -- public String getClassName() { -- return readClass(header + 2, new char[maxStringLength]); -- } -- -- /** -- * Returns the internal of name of the super class (see -- * {@link Type#getInternalName() getInternalName}). For interfaces, the -- * super class is {@link Object}. -- * -- * @return the internal name of super class, or null for -- * {@link Object} class. -- * -- * @see ClassVisitor#visit(int, int, String, String, String, String[]) -- */ -- public String getSuperName() { -- return readClass(header + 4, new char[maxStringLength]); -- } -- -- /** -- * Returns the internal names of the class's interfaces (see -- * {@link Type#getInternalName() getInternalName}). -- * -- * @return the array of internal names for all implemented interfaces or -- * null. -- * -- * @see ClassVisitor#visit(int, int, String, String, String, String[]) -- */ -- public String[] getInterfaces() { -- int index = header + 6; -- int n = readUnsignedShort(index); -- String[] interfaces = new String[n]; -- if (n > 0) { -- char[] buf = new char[maxStringLength]; -- for (int i = 0; i < n; ++i) { -- index += 2; -- interfaces[i] = readClass(index, buf); -- } -- } -- return interfaces; -- } -- -- /** -- * Copies the constant pool data into the given {@link ClassWriter}. Should -- * be called before the {@link #accept(ClassVisitor,int)} method. -- * -- * @param classWriter -- * the {@link ClassWriter} to copy constant pool into. -- */ -- void copyPool(final ClassWriter classWriter) { -- char[] buf = new char[maxStringLength]; -- int ll = items.length; -- Item[] items2 = new Item[ll]; -- for (int i = 1; i < ll; i++) { -- int index = items[i]; -- int tag = b[index - 1]; -- Item item = new Item(i); -- int nameType; -- switch (tag) { -- case ClassWriter.FIELD: -- case ClassWriter.METH: -- case ClassWriter.IMETH: -- nameType = items[readUnsignedShort(index + 2)]; -- item.set(tag, readClass(index, buf), readUTF8(nameType, buf), -- readUTF8(nameType + 2, buf)); -- break; -- case ClassWriter.INT: -- item.set(readInt(index)); -- break; -- case ClassWriter.FLOAT: -- item.set(Float.intBitsToFloat(readInt(index))); -- break; -- case ClassWriter.NAME_TYPE: -- item.set(tag, readUTF8(index, buf), readUTF8(index + 2, buf), -- null); -- break; -- case ClassWriter.LONG: -- item.set(readLong(index)); -- ++i; -- break; -- case ClassWriter.DOUBLE: -- item.set(Double.longBitsToDouble(readLong(index))); -- ++i; -- break; -- case ClassWriter.UTF8: { -- String s = strings[i]; -- if (s == null) { -- index = items[i]; -- s = strings[i] = readUTF(index + 2, -- readUnsignedShort(index), buf); -- } -- item.set(tag, s, null, null); -- break; -- } -- case ClassWriter.HANDLE: { -- int fieldOrMethodRef = items[readUnsignedShort(index + 1)]; -- nameType = items[readUnsignedShort(fieldOrMethodRef + 2)]; -- item.set(ClassWriter.HANDLE_BASE + readByte(index), -- readClass(fieldOrMethodRef, buf), -- readUTF8(nameType, buf), readUTF8(nameType + 2, buf)); -- break; -- } -- case ClassWriter.INDY: -- if (classWriter.bootstrapMethods == null) { -- copyBootstrapMethods(classWriter, items2, buf); -- } -- nameType = items[readUnsignedShort(index + 2)]; -- item.set(readUTF8(nameType, buf), readUTF8(nameType + 2, buf), -- readUnsignedShort(index)); -- break; -- // case ClassWriter.STR: -- // case ClassWriter.CLASS: -- // case ClassWriter.MTYPE -- default: -- item.set(tag, readUTF8(index, buf), null, null); -- break; -- } -- -- int index2 = item.hashCode % items2.length; -- item.next = items2[index2]; -- items2[index2] = item; -- } -- -- int off = items[1] - 1; -- classWriter.pool.putByteArray(b, off, header - off); -- classWriter.items = items2; -- classWriter.threshold = (int) (0.75d * ll); -- classWriter.index = ll; -- } -- -- /** -- * Copies the bootstrap method data into the given {@link ClassWriter}. -- * Should be called before the {@link #accept(ClassVisitor,int)} method. -- * -- * @param classWriter -- * the {@link ClassWriter} to copy bootstrap methods into. -- */ -- private void copyBootstrapMethods(final ClassWriter classWriter, -- final Item[] items, final char[] c) { -- // finds the "BootstrapMethods" attribute -- int u = getAttributes(); -- boolean found = false; -- for (int i = readUnsignedShort(u); i > 0; --i) { -- String attrName = readUTF8(u + 2, c); -- if ("BootstrapMethods".equals(attrName)) { -- found = true; -- break; -- } -- u += 6 + readInt(u + 4); -- } -- if (!found) { -- return; -- } -- // copies the bootstrap methods in the class writer -- int boostrapMethodCount = readUnsignedShort(u + 8); -- for (int j = 0, v = u + 10; j < boostrapMethodCount; j++) { -- int position = v - u - 10; -- int hashCode = readConst(readUnsignedShort(v), c).hashCode(); -- for (int k = readUnsignedShort(v + 2); k > 0; --k) { -- hashCode ^= readConst(readUnsignedShort(v + 4), c).hashCode(); -- v += 2; -- } -- v += 4; -- Item item = new Item(j); -- item.set(position, hashCode & 0x7FFFFFFF); -- int index = item.hashCode % items.length; -- item.next = items[index]; -- items[index] = item; -- } -- int attrSize = readInt(u + 4); -- ByteVector bootstrapMethods = new ByteVector(attrSize + 62); -- bootstrapMethods.putByteArray(b, u + 10, attrSize - 2); -- classWriter.bootstrapMethodsCount = boostrapMethodCount; -- classWriter.bootstrapMethods = bootstrapMethods; -- } -- -- /** -- * Constructs a new {@link ClassReader} object. -- * -- * @param is -- * an input stream from which to read the class. -- * @throws IOException -- * if a problem occurs during reading. -- */ -- public ClassReader(final InputStream is) throws IOException { -- this(readClass(is, false)); -- } -- -- /** -- * Constructs a new {@link ClassReader} object. -- * -- * @param name -- * the binary qualified name of the class to be read. -- * @throws IOException -- * if an exception occurs during reading. -- */ -- public ClassReader(final String name) throws IOException { -- this(readClass( -- ClassLoader.getSystemResourceAsStream(name.replace('.', '/') -- + ".class"), true)); -- } -- -- /** -- * Reads the bytecode of a class. -- * -- * @param is -- * an input stream from which to read the class. -- * @param close -- * true to close the input stream after reading. -- * @return the bytecode read from the given input stream. -- * @throws IOException -- * if a problem occurs during reading. -- */ -- private static byte[] readClass(final InputStream is, boolean close) -- throws IOException { -- if (is == null) { -- throw new IOException("Class not found"); -- } -- try { -- byte[] b = new byte[is.available()]; -- int len = 0; -- while (true) { -- int n = is.read(b, len, b.length - len); -- if (n == -1) { -- if (len < b.length) { -- byte[] c = new byte[len]; -- System.arraycopy(b, 0, c, 0, len); -- b = c; -- } -- return b; -- } -- len += n; -- if (len == b.length) { -- int last = is.read(); -- if (last < 0) { -- return b; -- } -- byte[] c = new byte[b.length + 1000]; -- System.arraycopy(b, 0, c, 0, len); -- c[len++] = (byte) last; -- b = c; -- } -- } -- } finally { -- if (close) { -- is.close(); -- } -- } -- } -- -- // ------------------------------------------------------------------------ -- // Public methods -- // ------------------------------------------------------------------------ -- -- /** -- * Makes the given visitor visit the Java class of this {@link ClassReader} -- * . This class is the one specified in the constructor (see -- * {@link #ClassReader(byte[]) ClassReader}). -- * -- * @param classVisitor -- * the visitor that must visit this class. -- * @param flags -- * option flags that can be used to modify the default behavior -- * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES} -- * , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. -- */ -- public void accept(final ClassVisitor classVisitor, final int flags) { -- accept(classVisitor, new Attribute[0], flags); -- } -- -- /** -- * Makes the given visitor visit the Java class of this {@link ClassReader}. -- * This class is the one specified in the constructor (see -- * {@link #ClassReader(byte[]) ClassReader}). -- * -- * @param classVisitor -- * the visitor that must visit this class. -- * @param attrs -- * prototypes of the attributes that must be parsed during the -- * visit of the class. Any attribute whose type is not equal to -- * the type of one the prototypes will not be parsed: its byte -- * array value will be passed unchanged to the ClassWriter. -- * This may corrupt it if this value contains references to -- * the constant pool, or has syntactic or semantic links with a -- * class element that has been transformed by a class adapter -- * between the reader and the writer. -- * @param flags -- * option flags that can be used to modify the default behavior -- * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES} -- * , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. -- */ -- public void accept(final ClassVisitor classVisitor, -- final Attribute[] attrs, final int flags) { -- int u = header; // current offset in the class file -- char[] c = new char[maxStringLength]; // buffer used to read strings -- -- Context context = new Context(); -- context.attrs = attrs; -- context.flags = flags; -- context.buffer = c; -- -- // reads the class declaration -- int access = readUnsignedShort(u); -- String name = readClass(u + 2, c); -- String superClass = readClass(u + 4, c); -- String[] interfaces = new String[readUnsignedShort(u + 6)]; -- u += 8; -- for (int i = 0; i < interfaces.length; ++i) { -- interfaces[i] = readClass(u, c); -- u += 2; -- } -- -- // reads the class attributes -- String signature = null; -- String sourceFile = null; -- String sourceDebug = null; -- String enclosingOwner = null; -- String enclosingName = null; -- String enclosingDesc = null; -- int anns = 0; -- int ianns = 0; -- int tanns = 0; -- int itanns = 0; -- int innerClasses = 0; -- Attribute attributes = null; -- -- u = getAttributes(); -- for (int i = readUnsignedShort(u); i > 0; --i) { -- String attrName = readUTF8(u + 2, c); -- // tests are sorted in decreasing frequency order -- // (based on frequencies observed on typical classes) -- if ("SourceFile".equals(attrName)) { -- sourceFile = readUTF8(u + 8, c); -- } else if ("InnerClasses".equals(attrName)) { -- innerClasses = u + 8; -- } else if ("EnclosingMethod".equals(attrName)) { -- enclosingOwner = readClass(u + 8, c); -- int item = readUnsignedShort(u + 10); -- if (item != 0) { -- enclosingName = readUTF8(items[item], c); -- enclosingDesc = readUTF8(items[item] + 2, c); -- } -- } else if (SIGNATURES && "Signature".equals(attrName)) { -- signature = readUTF8(u + 8, c); -- } else if (ANNOTATIONS -- && "RuntimeVisibleAnnotations".equals(attrName)) { -- anns = u + 8; -- } else if (ANNOTATIONS -- && "RuntimeVisibleTypeAnnotations".equals(attrName)) { -- tanns = u + 8; -- } else if ("Deprecated".equals(attrName)) { -- access |= Opcodes.ACC_DEPRECATED; -- } else if ("Synthetic".equals(attrName)) { -- access |= Opcodes.ACC_SYNTHETIC -- | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; -- } else if ("SourceDebugExtension".equals(attrName)) { -- int len = readInt(u + 4); -- sourceDebug = readUTF(u + 8, len, new char[len]); -- } else if (ANNOTATIONS -- && "RuntimeInvisibleAnnotations".equals(attrName)) { -- ianns = u + 8; -- } else if (ANNOTATIONS -- && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { -- itanns = u + 8; -- } else if ("BootstrapMethods".equals(attrName)) { -- int[] bootstrapMethods = new int[readUnsignedShort(u + 8)]; -- for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) { -- bootstrapMethods[j] = v; -- v += 2 + readUnsignedShort(v + 2) << 1; -- } -- context.bootstrapMethods = bootstrapMethods; -- } else { -- Attribute attr = readAttribute(attrs, attrName, u + 8, -- readInt(u + 4), c, -1, null); -- if (attr != null) { -- attr.next = attributes; -- attributes = attr; -- } -- } -- u += 6 + readInt(u + 4); -- } -- -- // visits the class declaration -- classVisitor.visit(readInt(items[1] - 7), access, name, signature, -- superClass, interfaces); -- -- // visits the source and debug info -- if ((flags & SKIP_DEBUG) == 0 -- && (sourceFile != null || sourceDebug != null)) { -- classVisitor.visitSource(sourceFile, sourceDebug); -- } -- -- // visits the outer class -- if (enclosingOwner != null) { -- classVisitor.visitOuterClass(enclosingOwner, enclosingName, -- enclosingDesc); -- } -- -- // visits the class annotations and type annotations -- if (ANNOTATIONS && anns != 0) { -- for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { -- v = readAnnotationValues(v + 2, c, true, -- classVisitor.visitAnnotation(readUTF8(v, c), true)); -- } -- } -- if (ANNOTATIONS && ianns != 0) { -- for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { -- v = readAnnotationValues(v + 2, c, true, -- classVisitor.visitAnnotation(readUTF8(v, c), false)); -- } -- } -- if (ANNOTATIONS && tanns != 0) { -- for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { -- v = readAnnotationTarget(context, v); -- v = readAnnotationValues(v + 2, c, true, -- classVisitor.visitTypeAnnotation(context.typeRef, -- context.typePath, readUTF8(v, c), true)); -- } -- } -- if (ANNOTATIONS && itanns != 0) { -- for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { -- v = readAnnotationTarget(context, v); -- v = readAnnotationValues(v + 2, c, true, -- classVisitor.visitTypeAnnotation(context.typeRef, -- context.typePath, readUTF8(v, c), false)); -- } -- } -- -- // visits the attributes -- while (attributes != null) { -- Attribute attr = attributes.next; -- attributes.next = null; -- classVisitor.visitAttribute(attributes); -- attributes = attr; -- } -- -- // visits the inner classes -- if (innerClasses != 0) { -- int v = innerClasses + 2; -- for (int i = readUnsignedShort(innerClasses); i > 0; --i) { -- classVisitor.visitInnerClass(readClass(v, c), -- readClass(v + 2, c), readUTF8(v + 4, c), -- readUnsignedShort(v + 6)); -- v += 8; -- } -- } -- -- // visits the fields and methods -- u = header + 10 + 2 * interfaces.length; -- for (int i = readUnsignedShort(u - 2); i > 0; --i) { -- u = readField(classVisitor, context, u); -- } -- u += 2; -- for (int i = readUnsignedShort(u - 2); i > 0; --i) { -- u = readMethod(classVisitor, context, u); -- } -- -- // visits the end of the class -- classVisitor.visitEnd(); -- } -- -- /** -- * Reads a field and makes the given visitor visit it. -- * -- * @param classVisitor -- * the visitor that must visit the field. -- * @param context -- * information about the class being parsed. -- * @param u -- * the start offset of the field in the class file. -- * @return the offset of the first byte following the field in the class. -- */ -- private int readField(final ClassVisitor classVisitor, -- final Context context, int u) { -- // reads the field declaration -- char[] c = context.buffer; -- int access = readUnsignedShort(u); -- String name = readUTF8(u + 2, c); -- String desc = readUTF8(u + 4, c); -- u += 6; -- -- // reads the field attributes -- String signature = null; -- int anns = 0; -- int ianns = 0; -- int tanns = 0; -- int itanns = 0; -- Object value = null; -- Attribute attributes = null; -- -- for (int i = readUnsignedShort(u); i > 0; --i) { -- String attrName = readUTF8(u + 2, c); -- // tests are sorted in decreasing frequency order -- // (based on frequencies observed on typical classes) -- if ("ConstantValue".equals(attrName)) { -- int item = readUnsignedShort(u + 8); -- value = item == 0 ? null : readConst(item, c); -- } else if (SIGNATURES && "Signature".equals(attrName)) { -- signature = readUTF8(u + 8, c); -- } else if ("Deprecated".equals(attrName)) { -- access |= Opcodes.ACC_DEPRECATED; -- } else if ("Synthetic".equals(attrName)) { -- access |= Opcodes.ACC_SYNTHETIC -- | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; -- } else if (ANNOTATIONS -- && "RuntimeVisibleAnnotations".equals(attrName)) { -- anns = u + 8; -- } else if (ANNOTATIONS -- && "RuntimeVisibleTypeAnnotations".equals(attrName)) { -- tanns = u + 8; -- } else if (ANNOTATIONS -- && "RuntimeInvisibleAnnotations".equals(attrName)) { -- ianns = u + 8; -- } else if (ANNOTATIONS -- && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { -- itanns = u + 8; -- } else { -- Attribute attr = readAttribute(context.attrs, attrName, u + 8, -- readInt(u + 4), c, -1, null); -- if (attr != null) { -- attr.next = attributes; -- attributes = attr; -- } -- } -- u += 6 + readInt(u + 4); -- } -- u += 2; -- -- // visits the field declaration -- FieldVisitor fv = classVisitor.visitField(access, name, desc, -- signature, value); -- if (fv == null) { -- return u; -- } -- -- // visits the field annotations and type annotations -- if (ANNOTATIONS && anns != 0) { -- for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { -- v = readAnnotationValues(v + 2, c, true, -- fv.visitAnnotation(readUTF8(v, c), true)); -- } -- } -- if (ANNOTATIONS && ianns != 0) { -- for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { -- v = readAnnotationValues(v + 2, c, true, -- fv.visitAnnotation(readUTF8(v, c), false)); -- } -- } -- if (ANNOTATIONS && tanns != 0) { -- for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { -- v = readAnnotationTarget(context, v); -- v = readAnnotationValues(v + 2, c, true, -- fv.visitTypeAnnotation(context.typeRef, -- context.typePath, readUTF8(v, c), true)); -- } -- } -- if (ANNOTATIONS && itanns != 0) { -- for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { -- v = readAnnotationTarget(context, v); -- v = readAnnotationValues(v + 2, c, true, -- fv.visitTypeAnnotation(context.typeRef, -- context.typePath, readUTF8(v, c), false)); -- } -- } -- -- // visits the field attributes -- while (attributes != null) { -- Attribute attr = attributes.next; -- attributes.next = null; -- fv.visitAttribute(attributes); -- attributes = attr; -- } -- -- // visits the end of the field -- fv.visitEnd(); -- -- return u; -- } -- -- /** -- * Reads a method and makes the given visitor visit it. -- * -- * @param classVisitor -- * the visitor that must visit the method. -- * @param context -- * information about the class being parsed. -- * @param u -- * the start offset of the method in the class file. -- * @return the offset of the first byte following the method in the class. -- */ -- private int readMethod(final ClassVisitor classVisitor, -- final Context context, int u) { -- // reads the method declaration -- char[] c = context.buffer; -- context.access = readUnsignedShort(u); -- context.name = readUTF8(u + 2, c); -- context.desc = readUTF8(u + 4, c); -- u += 6; -- -- // reads the method attributes -- int code = 0; -- int exception = 0; -- String[] exceptions = null; -- String signature = null; -- int methodParameters = 0; -- int anns = 0; -- int ianns = 0; -- int tanns = 0; -- int itanns = 0; -- int dann = 0; -- int mpanns = 0; -- int impanns = 0; -- int firstAttribute = u; -- Attribute attributes = null; -- -- for (int i = readUnsignedShort(u); i > 0; --i) { -- String attrName = readUTF8(u + 2, c); -- // tests are sorted in decreasing frequency order -- // (based on frequencies observed on typical classes) -- if ("Code".equals(attrName)) { -- if ((context.flags & SKIP_CODE) == 0) { -- code = u + 8; -- } -- } else if ("Exceptions".equals(attrName)) { -- exceptions = new String[readUnsignedShort(u + 8)]; -- exception = u + 10; -- for (int j = 0; j < exceptions.length; ++j) { -- exceptions[j] = readClass(exception, c); -- exception += 2; -- } -- } else if (SIGNATURES && "Signature".equals(attrName)) { -- signature = readUTF8(u + 8, c); -- } else if ("Deprecated".equals(attrName)) { -- context.access |= Opcodes.ACC_DEPRECATED; -- } else if (ANNOTATIONS -- && "RuntimeVisibleAnnotations".equals(attrName)) { -- anns = u + 8; -- } else if (ANNOTATIONS -- && "RuntimeVisibleTypeAnnotations".equals(attrName)) { -- tanns = u + 8; -- } else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) { -- dann = u + 8; -- } else if ("Synthetic".equals(attrName)) { -- context.access |= Opcodes.ACC_SYNTHETIC -- | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; -- } else if (ANNOTATIONS -- && "RuntimeInvisibleAnnotations".equals(attrName)) { -- ianns = u + 8; -- } else if (ANNOTATIONS -- && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { -- itanns = u + 8; -- } else if (ANNOTATIONS -- && "RuntimeVisibleParameterAnnotations".equals(attrName)) { -- mpanns = u + 8; -- } else if (ANNOTATIONS -- && "RuntimeInvisibleParameterAnnotations".equals(attrName)) { -- impanns = u + 8; -- } else if ("MethodParameters".equals(attrName)) { -- methodParameters = u + 8; -- } else { -- Attribute attr = readAttribute(context.attrs, attrName, u + 8, -- readInt(u + 4), c, -1, null); -- if (attr != null) { -- attr.next = attributes; -- attributes = attr; -- } -- } -- u += 6 + readInt(u + 4); -- } -- u += 2; -- -- // visits the method declaration -- MethodVisitor mv = classVisitor.visitMethod(context.access, -- context.name, context.desc, signature, exceptions); -- if (mv == null) { -- return u; -- } -- -- /* -- * if the returned MethodVisitor is in fact a MethodWriter, it means -- * there is no method adapter between the reader and the writer. If, in -- * addition, the writer's constant pool was copied from this reader -- * (mw.cw.cr == this), and the signature and exceptions of the method -- * have not been changed, then it is possible to skip all visit events -- * and just copy the original code of the method to the writer (the -- * access, name and descriptor can have been changed, this is not -- * important since they are not copied as is from the reader). -- */ -- if (WRITER && mv instanceof MethodWriter) { -- MethodWriter mw = (MethodWriter) mv; -- if (mw.cw.cr == this && signature == mw.signature) { -- boolean sameExceptions = false; -- if (exceptions == null) { -- sameExceptions = mw.exceptionCount == 0; -- } else if (exceptions.length == mw.exceptionCount) { -- sameExceptions = true; -- for (int j = exceptions.length - 1; j >= 0; --j) { -- exception -= 2; -- if (mw.exceptions[j] != readUnsignedShort(exception)) { -- sameExceptions = false; -- break; -- } -- } -- } -- if (sameExceptions) { -- /* -- * we do not copy directly the code into MethodWriter to -- * save a byte array copy operation. The real copy will be -- * done in ClassWriter.toByteArray(). -- */ -- mw.classReaderOffset = firstAttribute; -- mw.classReaderLength = u - firstAttribute; -- return u; -- } -- } -- } -- -- // visit the method parameters -- if (methodParameters != 0) { -- for (int i = b[methodParameters] & 0xFF, v = methodParameters + 1; i > 0; --i, v = v + 4) { -- mv.visitParameter(readUTF8(v, c), readUnsignedShort(v + 2)); -- } -- } -- -- // visits the method annotations -- if (ANNOTATIONS && dann != 0) { -- AnnotationVisitor dv = mv.visitAnnotationDefault(); -- readAnnotationValue(dann, c, null, dv); -- if (dv != null) { -- dv.visitEnd(); -- } -- } -- if (ANNOTATIONS && anns != 0) { -- for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { -- v = readAnnotationValues(v + 2, c, true, -- mv.visitAnnotation(readUTF8(v, c), true)); -- } -- } -- if (ANNOTATIONS && ianns != 0) { -- for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { -- v = readAnnotationValues(v + 2, c, true, -- mv.visitAnnotation(readUTF8(v, c), false)); -- } -- } -- if (ANNOTATIONS && tanns != 0) { -- for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { -- v = readAnnotationTarget(context, v); -- v = readAnnotationValues(v + 2, c, true, -- mv.visitTypeAnnotation(context.typeRef, -- context.typePath, readUTF8(v, c), true)); -- } -- } -- if (ANNOTATIONS && itanns != 0) { -- for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { -- v = readAnnotationTarget(context, v); -- v = readAnnotationValues(v + 2, c, true, -- mv.visitTypeAnnotation(context.typeRef, -- context.typePath, readUTF8(v, c), false)); -- } -- } -- if (ANNOTATIONS && mpanns != 0) { -- readParameterAnnotations(mv, context, mpanns, true); -- } -- if (ANNOTATIONS && impanns != 0) { -- readParameterAnnotations(mv, context, impanns, false); -- } -- -- // visits the method attributes -- while (attributes != null) { -- Attribute attr = attributes.next; -- attributes.next = null; -- mv.visitAttribute(attributes); -- attributes = attr; -- } -- -- // visits the method code -- if (code != 0) { -- mv.visitCode(); -- readCode(mv, context, code); -- } -- -- // visits the end of the method -- mv.visitEnd(); -- -- return u; -- } -- -- /** -- * Reads the bytecode of a method and makes the given visitor visit it. -- * -- * @param mv -- * the visitor that must visit the method's code. -- * @param context -- * information about the class being parsed. -- * @param u -- * the start offset of the code attribute in the class file. -- */ -- private void readCode(final MethodVisitor mv, final Context context, int u) { -- // reads the header -- byte[] b = this.b; -- char[] c = context.buffer; -- int maxStack = readUnsignedShort(u); -- int maxLocals = readUnsignedShort(u + 2); -- int codeLength = readInt(u + 4); -- u += 8; -- -- // reads the bytecode to find the labels -- int codeStart = u; -- int codeEnd = u + codeLength; -- Label[] labels = context.labels = new Label[codeLength + 2]; -- readLabel(codeLength + 1, labels); -- while (u < codeEnd) { -- int offset = u - codeStart; -- int opcode = b[u] & 0xFF; -- switch (ClassWriter.TYPE[opcode]) { -- case ClassWriter.NOARG_INSN: -- case ClassWriter.IMPLVAR_INSN: -- u += 1; -- break; -- case ClassWriter.LABEL_INSN: -- readLabel(offset + readShort(u + 1), labels); -- u += 3; -- break; -- case ClassWriter.LABELW_INSN: -- readLabel(offset + readInt(u + 1), labels); -- u += 5; -- break; -- case ClassWriter.WIDE_INSN: -- opcode = b[u + 1] & 0xFF; -- if (opcode == Opcodes.IINC) { -- u += 6; -- } else { -- u += 4; -- } -- break; -- case ClassWriter.TABL_INSN: -- // skips 0 to 3 padding bytes -- u = u + 4 - (offset & 3); -- // reads instruction -- readLabel(offset + readInt(u), labels); -- for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) { -- readLabel(offset + readInt(u + 12), labels); -- u += 4; -- } -- u += 12; -- break; -- case ClassWriter.LOOK_INSN: -- // skips 0 to 3 padding bytes -- u = u + 4 - (offset & 3); -- // reads instruction -- readLabel(offset + readInt(u), labels); -- for (int i = readInt(u + 4); i > 0; --i) { -- readLabel(offset + readInt(u + 12), labels); -- u += 8; -- } -- u += 8; -- break; -- case ClassWriter.VAR_INSN: -- case ClassWriter.SBYTE_INSN: -- case ClassWriter.LDC_INSN: -- u += 2; -- break; -- case ClassWriter.SHORT_INSN: -- case ClassWriter.LDCW_INSN: -- case ClassWriter.FIELDORMETH_INSN: -- case ClassWriter.TYPE_INSN: -- case ClassWriter.IINC_INSN: -- u += 3; -- break; -- case ClassWriter.ITFMETH_INSN: -- case ClassWriter.INDYMETH_INSN: -- u += 5; -- break; -- // case MANA_INSN: -- default: -- u += 4; -- break; -- } -- } -- -- // reads the try catch entries to find the labels, and also visits them -- for (int i = readUnsignedShort(u); i > 0; --i) { -- Label start = readLabel(readUnsignedShort(u + 2), labels); -- Label end = readLabel(readUnsignedShort(u + 4), labels); -- Label handler = readLabel(readUnsignedShort(u + 6), labels); -- String type = readUTF8(items[readUnsignedShort(u + 8)], c); -- mv.visitTryCatchBlock(start, end, handler, type); -- u += 8; -- } -- u += 2; -- -- // reads the code attributes -- int[] tanns = null; // start index of each visible type annotation -- int[] itanns = null; // start index of each invisible type annotation -- int tann = 0; // current index in tanns array -- int itann = 0; // current index in itanns array -- int ntoff = -1; // next visible type annotation code offset -- int nitoff = -1; // next invisible type annotation code offset -- int varTable = 0; -- int varTypeTable = 0; -- boolean zip = true; -- boolean unzip = (context.flags & EXPAND_FRAMES) != 0; -- int stackMap = 0; -- int stackMapSize = 0; -- int frameCount = 0; -- Context frame = null; -- Attribute attributes = null; -- -- for (int i = readUnsignedShort(u); i > 0; --i) { -- String attrName = readUTF8(u + 2, c); -- if ("LocalVariableTable".equals(attrName)) { -- if ((context.flags & SKIP_DEBUG) == 0) { -- varTable = u + 8; -- for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) { -- int label = readUnsignedShort(v + 10); -- if (labels[label] == null) { -- readLabel(label, labels).status |= Label.DEBUG; -- } -- label += readUnsignedShort(v + 12); -- if (labels[label] == null) { -- readLabel(label, labels).status |= Label.DEBUG; -- } -- v += 10; -- } -- } -- } else if ("LocalVariableTypeTable".equals(attrName)) { -- varTypeTable = u + 8; -- } else if ("LineNumberTable".equals(attrName)) { -- if ((context.flags & SKIP_DEBUG) == 0) { -- for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) { -- int label = readUnsignedShort(v + 10); -- if (labels[label] == null) { -- readLabel(label, labels).status |= Label.DEBUG; -- } -- labels[label].line = readUnsignedShort(v + 12); -- v += 4; -- } -- } -- } else if (ANNOTATIONS -- && "RuntimeVisibleTypeAnnotations".equals(attrName)) { -- tanns = readTypeAnnotations(mv, context, u + 8, true); -- ntoff = tanns.length == 0 || readByte(tanns[0]) < 0x43 ? -1 -- : readUnsignedShort(tanns[0] + 1); -- } else if (ANNOTATIONS -- && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { -- itanns = readTypeAnnotations(mv, context, u + 8, false); -- nitoff = itanns.length == 0 || readByte(itanns[0]) < 0x43 ? -1 -- : readUnsignedShort(itanns[0] + 1); -- } else if (FRAMES && "StackMapTable".equals(attrName)) { -- if ((context.flags & SKIP_FRAMES) == 0) { -- stackMap = u + 10; -- stackMapSize = readInt(u + 4); -- frameCount = readUnsignedShort(u + 8); -- } -- /* -- * here we do not extract the labels corresponding to the -- * attribute content. This would require a full parsing of the -- * attribute, which would need to be repeated in the second -- * phase (see below). Instead the content of the attribute is -- * read one frame at a time (i.e. after a frame has been -- * visited, the next frame is read), and the labels it contains -- * are also extracted one frame at a time. Thanks to the -- * ordering of frames, having only a "one frame lookahead" is -- * not a problem, i.e. it is not possible to see an offset -- * smaller than the offset of the current insn and for which no -- * Label exist. -- */ -- /* -- * This is not true for UNINITIALIZED type offsets. We solve -- * this by parsing the stack map table without a full decoding -- * (see below). -- */ -- } else if (FRAMES && "StackMap".equals(attrName)) { -- if ((context.flags & SKIP_FRAMES) == 0) { -- zip = false; -- stackMap = u + 10; -- stackMapSize = readInt(u + 4); -- frameCount = readUnsignedShort(u + 8); -- } -- /* -- * IMPORTANT! here we assume that the frames are ordered, as in -- * the StackMapTable attribute, although this is not guaranteed -- * by the attribute format. -- */ -- } else { -- for (int j = 0; j < context.attrs.length; ++j) { -- if (context.attrs[j].type.equals(attrName)) { -- Attribute attr = context.attrs[j].read(this, u + 8, -- readInt(u + 4), c, codeStart - 8, labels); -- if (attr != null) { -- attr.next = attributes; -- attributes = attr; -- } -- } -- } -- } -- u += 6 + readInt(u + 4); -- } -- u += 2; -- -- // generates the first (implicit) stack map frame -- if (FRAMES && stackMap != 0) { -- /* -- * for the first explicit frame the offset is not offset_delta + 1 -- * but only offset_delta; setting the implicit frame offset to -1 -- * allow the use of the "offset_delta + 1" rule in all cases -- */ -- frame = context; -- frame.offset = -1; -- frame.mode = 0; -- frame.localCount = 0; -- frame.localDiff = 0; -- frame.stackCount = 0; -- frame.local = new Object[maxLocals]; -- frame.stack = new Object[maxStack]; -- if (unzip) { -- getImplicitFrame(context); -- } -- /* -- * Finds labels for UNINITIALIZED frame types. Instead of decoding -- * each element of the stack map table, we look for 3 consecutive -- * bytes that "look like" an UNINITIALIZED type (tag 8, offset -- * within code bounds, NEW instruction at this offset). We may find -- * false positives (i.e. not real UNINITIALIZED types), but this -- * should be rare, and the only consequence will be the creation of -- * an unneeded label. This is better than creating a label for each -- * NEW instruction, and faster than fully decoding the whole stack -- * map table. -- */ -- for (int i = stackMap; i < stackMap + stackMapSize - 2; ++i) { -- if (b[i] == 8) { // UNINITIALIZED FRAME TYPE -- int v = readUnsignedShort(i + 1); -- if (v >= 0 && v < codeLength) { -- if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) { -- readLabel(v, labels); -- } -- } -- } -- } -- } -- -- // visits the instructions -- u = codeStart; -- while (u < codeEnd) { -- int offset = u - codeStart; -- -- // visits the label and line number for this offset, if any -- Label l = labels[offset]; -- if (l != null) { -- mv.visitLabel(l); -- if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) { -- mv.visitLineNumber(l.line, l); -- } -- } -- -- // visits the frame for this offset, if any -- while (FRAMES && frame != null -- && (frame.offset == offset || frame.offset == -1)) { -- // if there is a frame for this offset, makes the visitor visit -- // it, and reads the next frame if there is one. -- if (frame.offset != -1) { -- if (!zip || unzip) { -- mv.visitFrame(Opcodes.F_NEW, frame.localCount, -- frame.local, frame.stackCount, frame.stack); -- } else { -- mv.visitFrame(frame.mode, frame.localDiff, frame.local, -- frame.stackCount, frame.stack); -- } -- } -- if (frameCount > 0) { -- stackMap = readFrame(stackMap, zip, unzip, frame); -- --frameCount; -- } else { -- frame = null; -- } -- } -- -- // visits the instruction at this offset -- int opcode = b[u] & 0xFF; -- switch (ClassWriter.TYPE[opcode]) { -- case ClassWriter.NOARG_INSN: -- mv.visitInsn(opcode); -- u += 1; -- break; -- case ClassWriter.IMPLVAR_INSN: -- if (opcode > Opcodes.ISTORE) { -- opcode -= 59; // ISTORE_0 -- mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), -- opcode & 0x3); -- } else { -- opcode -= 26; // ILOAD_0 -- mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3); -- } -- u += 1; -- break; -- case ClassWriter.LABEL_INSN: -- mv.visitJumpInsn(opcode, labels[offset + readShort(u + 1)]); -- u += 3; -- break; -- case ClassWriter.LABELW_INSN: -- mv.visitJumpInsn(opcode - 33, labels[offset + readInt(u + 1)]); -- u += 5; -- break; -- case ClassWriter.WIDE_INSN: -- opcode = b[u + 1] & 0xFF; -- if (opcode == Opcodes.IINC) { -- mv.visitIincInsn(readUnsignedShort(u + 2), readShort(u + 4)); -- u += 6; -- } else { -- mv.visitVarInsn(opcode, readUnsignedShort(u + 2)); -- u += 4; -- } -- break; -- case ClassWriter.TABL_INSN: { -- // skips 0 to 3 padding bytes -- u = u + 4 - (offset & 3); -- // reads instruction -- int label = offset + readInt(u); -- int min = readInt(u + 4); -- int max = readInt(u + 8); -- Label[] table = new Label[max - min + 1]; -- u += 12; -- for (int i = 0; i < table.length; ++i) { -- table[i] = labels[offset + readInt(u)]; -- u += 4; -- } -- mv.visitTableSwitchInsn(min, max, labels[label], table); -- break; -- } -- case ClassWriter.LOOK_INSN: { -- // skips 0 to 3 padding bytes -- u = u + 4 - (offset & 3); -- // reads instruction -- int label = offset + readInt(u); -- int len = readInt(u + 4); -- int[] keys = new int[len]; -- Label[] values = new Label[len]; -- u += 8; -- for (int i = 0; i < len; ++i) { -- keys[i] = readInt(u); -- values[i] = labels[offset + readInt(u + 4)]; -- u += 8; -- } -- mv.visitLookupSwitchInsn(labels[label], keys, values); -- break; -- } -- case ClassWriter.VAR_INSN: -- mv.visitVarInsn(opcode, b[u + 1] & 0xFF); -- u += 2; -- break; -- case ClassWriter.SBYTE_INSN: -- mv.visitIntInsn(opcode, b[u + 1]); -- u += 2; -- break; -- case ClassWriter.SHORT_INSN: -- mv.visitIntInsn(opcode, readShort(u + 1)); -- u += 3; -- break; -- case ClassWriter.LDC_INSN: -- mv.visitLdcInsn(readConst(b[u + 1] & 0xFF, c)); -- u += 2; -- break; -- case ClassWriter.LDCW_INSN: -- mv.visitLdcInsn(readConst(readUnsignedShort(u + 1), c)); -- u += 3; -- break; -- case ClassWriter.FIELDORMETH_INSN: -- case ClassWriter.ITFMETH_INSN: { -- int cpIndex = items[readUnsignedShort(u + 1)]; -- boolean itf = b[cpIndex - 1] == ClassWriter.IMETH; -- String iowner = readClass(cpIndex, c); -- cpIndex = items[readUnsignedShort(cpIndex + 2)]; -- String iname = readUTF8(cpIndex, c); -- String idesc = readUTF8(cpIndex + 2, c); -- if (opcode < Opcodes.INVOKEVIRTUAL) { -- mv.visitFieldInsn(opcode, iowner, iname, idesc); -- } else { -- mv.visitMethodInsn(opcode, iowner, iname, idesc, itf); -- } -- if (opcode == Opcodes.INVOKEINTERFACE) { -- u += 5; -- } else { -- u += 3; -- } -- break; -- } -- case ClassWriter.INDYMETH_INSN: { -- int cpIndex = items[readUnsignedShort(u + 1)]; -- int bsmIndex = context.bootstrapMethods[readUnsignedShort(cpIndex)]; -- Handle bsm = (Handle) readConst(readUnsignedShort(bsmIndex), c); -- int bsmArgCount = readUnsignedShort(bsmIndex + 2); -- Object[] bsmArgs = new Object[bsmArgCount]; -- bsmIndex += 4; -- for (int i = 0; i < bsmArgCount; i++) { -- bsmArgs[i] = readConst(readUnsignedShort(bsmIndex), c); -- bsmIndex += 2; -- } -- cpIndex = items[readUnsignedShort(cpIndex + 2)]; -- String iname = readUTF8(cpIndex, c); -- String idesc = readUTF8(cpIndex + 2, c); -- mv.visitInvokeDynamicInsn(iname, idesc, bsm, bsmArgs); -- u += 5; -- break; -- } -- case ClassWriter.TYPE_INSN: -- mv.visitTypeInsn(opcode, readClass(u + 1, c)); -- u += 3; -- break; -- case ClassWriter.IINC_INSN: -- mv.visitIincInsn(b[u + 1] & 0xFF, b[u + 2]); -- u += 3; -- break; -- // case MANA_INSN: -- default: -- mv.visitMultiANewArrayInsn(readClass(u + 1, c), b[u + 3] & 0xFF); -- u += 4; -- break; -- } -- -- // visit the instruction annotations, if any -- while (tanns != null && tann < tanns.length && ntoff <= offset) { -- if (ntoff == offset) { -- int v = readAnnotationTarget(context, tanns[tann]); -- readAnnotationValues(v + 2, c, true, -- mv.visitInsnAnnotation(context.typeRef, -- context.typePath, readUTF8(v, c), true)); -- } -- ntoff = ++tann >= tanns.length || readByte(tanns[tann]) < 0x43 ? -1 -- : readUnsignedShort(tanns[tann] + 1); -- } -- while (itanns != null && itann < itanns.length && nitoff <= offset) { -- if (nitoff == offset) { -- int v = readAnnotationTarget(context, itanns[itann]); -- readAnnotationValues(v + 2, c, true, -- mv.visitInsnAnnotation(context.typeRef, -- context.typePath, readUTF8(v, c), false)); -- } -- nitoff = ++itann >= itanns.length -- || readByte(itanns[itann]) < 0x43 ? -1 -- : readUnsignedShort(itanns[itann] + 1); -- } -- } -- if (labels[codeLength] != null) { -- mv.visitLabel(labels[codeLength]); -- } -- -- // visits the local variable tables -- if ((context.flags & SKIP_DEBUG) == 0 && varTable != 0) { -- int[] typeTable = null; -- if (varTypeTable != 0) { -- u = varTypeTable + 2; -- typeTable = new int[readUnsignedShort(varTypeTable) * 3]; -- for (int i = typeTable.length; i > 0;) { -- typeTable[--i] = u + 6; // signature -- typeTable[--i] = readUnsignedShort(u + 8); // index -- typeTable[--i] = readUnsignedShort(u); // start -- u += 10; -- } -- } -- u = varTable + 2; -- for (int i = readUnsignedShort(varTable); i > 0; --i) { -- int start = readUnsignedShort(u); -- int length = readUnsignedShort(u + 2); -- int index = readUnsignedShort(u + 8); -- String vsignature = null; -- if (typeTable != null) { -- for (int j = 0; j < typeTable.length; j += 3) { -- if (typeTable[j] == start && typeTable[j + 1] == index) { -- vsignature = readUTF8(typeTable[j + 2], c); -- break; -- } -- } -- } -- mv.visitLocalVariable(readUTF8(u + 4, c), readUTF8(u + 6, c), -- vsignature, labels[start], labels[start + length], -- index); -- u += 10; -- } -- } -- -- // visits the local variables type annotations -- if (tanns != null) { -- for (int i = 0; i < tanns.length; ++i) { -- if ((readByte(tanns[i]) >> 1) == (0x40 >> 1)) { -- int v = readAnnotationTarget(context, tanns[i]); -- v = readAnnotationValues(v + 2, c, true, -- mv.visitLocalVariableAnnotation(context.typeRef, -- context.typePath, context.start, -- context.end, context.index, readUTF8(v, c), -- true)); -- } -- } -- } -- if (itanns != null) { -- for (int i = 0; i < itanns.length; ++i) { -- if ((readByte(itanns[i]) >> 1) == (0x40 >> 1)) { -- int v = readAnnotationTarget(context, itanns[i]); -- v = readAnnotationValues(v + 2, c, true, -- mv.visitLocalVariableAnnotation(context.typeRef, -- context.typePath, context.start, -- context.end, context.index, readUTF8(v, c), -- false)); -- } -- } -- } -- -- // visits the code attributes -- while (attributes != null) { -- Attribute attr = attributes.next; -- attributes.next = null; -- mv.visitAttribute(attributes); -- attributes = attr; -- } -- -- // visits the max stack and max locals values -- mv.visitMaxs(maxStack, maxLocals); -- } -- -- /** -- * Parses a type annotation table to find the labels, and to visit the try -- * catch block annotations. -- * -- * @param u -- * the start offset of a type annotation table. -- * @param mv -- * the method visitor to be used to visit the try catch block -- * annotations. -- * @param context -- * information about the class being parsed. -- * @param visible -- * if the type annotation table to parse contains runtime visible -- * annotations. -- * @return the start offset of each type annotation in the parsed table. -- */ -- private int[] readTypeAnnotations(final MethodVisitor mv, -- final Context context, int u, boolean visible) { -- char[] c = context.buffer; -- int[] offsets = new int[readUnsignedShort(u)]; -- u += 2; -- for (int i = 0; i < offsets.length; ++i) { -- offsets[i] = u; -- int target = readInt(u); -- switch (target >>> 24) { -- case 0x00: // CLASS_TYPE_PARAMETER -- case 0x01: // METHOD_TYPE_PARAMETER -- case 0x16: // METHOD_FORMAL_PARAMETER -- u += 2; -- break; -- case 0x13: // FIELD -- case 0x14: // METHOD_RETURN -- case 0x15: // METHOD_RECEIVER -- u += 1; -- break; -- case 0x40: // LOCAL_VARIABLE -- case 0x41: // RESOURCE_VARIABLE -- for (int j = readUnsignedShort(u + 1); j > 0; --j) { -- int start = readUnsignedShort(u + 3); -- int length = readUnsignedShort(u + 5); -- readLabel(start, context.labels); -- readLabel(start + length, context.labels); -- u += 6; -- } -- u += 3; -- break; -- case 0x47: // CAST -- case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -- case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT -- case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -- case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT -- u += 4; -- break; -- // case 0x10: // CLASS_EXTENDS -- // case 0x11: // CLASS_TYPE_PARAMETER_BOUND -- // case 0x12: // METHOD_TYPE_PARAMETER_BOUND -- // case 0x17: // THROWS -- // case 0x42: // EXCEPTION_PARAMETER -- // case 0x43: // INSTANCEOF -- // case 0x44: // NEW -- // case 0x45: // CONSTRUCTOR_REFERENCE -- // case 0x46: // METHOD_REFERENCE -- default: -- u += 3; -- break; -- } -- int pathLength = readByte(u); -- if ((target >>> 24) == 0x42) { -- TypePath path = pathLength == 0 ? null : new TypePath(b, u); -- u += 1 + 2 * pathLength; -- u = readAnnotationValues(u + 2, c, true, -- mv.visitTryCatchAnnotation(target, path, -- readUTF8(u, c), visible)); -- } else { -- u = readAnnotationValues(u + 3 + 2 * pathLength, c, true, null); -- } -- } -- return offsets; -- } -- -- /** -- * Parses the header of a type annotation to extract its target_type and -- * target_path (the result is stored in the given context), and returns the -- * start offset of the rest of the type_annotation structure (i.e. the -- * offset to the type_index field, which is followed by -- * num_element_value_pairs and then the name,value pairs). -- * -- * @param context -- * information about the class being parsed. This is where the -- * extracted target_type and target_path must be stored. -- * @param u -- * the start offset of a type_annotation structure. -- * @return the start offset of the rest of the type_annotation structure. -- */ -- private int readAnnotationTarget(final Context context, int u) { -- int target = readInt(u); -- switch (target >>> 24) { -- case 0x00: // CLASS_TYPE_PARAMETER -- case 0x01: // METHOD_TYPE_PARAMETER -- case 0x16: // METHOD_FORMAL_PARAMETER -- target &= 0xFFFF0000; -- u += 2; -- break; -- case 0x13: // FIELD -- case 0x14: // METHOD_RETURN -- case 0x15: // METHOD_RECEIVER -- target &= 0xFF000000; -- u += 1; -- break; -- case 0x40: // LOCAL_VARIABLE -- case 0x41: { // RESOURCE_VARIABLE -- target &= 0xFF000000; -- int n = readUnsignedShort(u + 1); -- context.start = new Label[n]; -- context.end = new Label[n]; -- context.index = new int[n]; -- u += 3; -- for (int i = 0; i < n; ++i) { -- int start = readUnsignedShort(u); -- int length = readUnsignedShort(u + 2); -- context.start[i] = readLabel(start, context.labels); -- context.end[i] = readLabel(start + length, context.labels); -- context.index[i] = readUnsignedShort(u + 4); -- u += 6; -- } -- break; -- } -- case 0x47: // CAST -- case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -- case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT -- case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -- case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT -- target &= 0xFF0000FF; -- u += 4; -- break; -- // case 0x10: // CLASS_EXTENDS -- // case 0x11: // CLASS_TYPE_PARAMETER_BOUND -- // case 0x12: // METHOD_TYPE_PARAMETER_BOUND -- // case 0x17: // THROWS -- // case 0x42: // EXCEPTION_PARAMETER -- // case 0x43: // INSTANCEOF -- // case 0x44: // NEW -- // case 0x45: // CONSTRUCTOR_REFERENCE -- // case 0x46: // METHOD_REFERENCE -- default: -- target &= (target >>> 24) < 0x43 ? 0xFFFFFF00 : 0xFF000000; -- u += 3; -- break; -- } -- int pathLength = readByte(u); -- context.typeRef = target; -- context.typePath = pathLength == 0 ? null : new TypePath(b, u); -- return u + 1 + 2 * pathLength; -- } -- -- /** -- * Reads parameter annotations and makes the given visitor visit them. -- * -- * @param mv -- * the visitor that must visit the annotations. -- * @param context -- * information about the class being parsed. -- * @param v -- * start offset in {@link #b b} of the annotations to be read. -- * @param visible -- * true if the annotations to be read are visible at -- * runtime. -- */ -- private void readParameterAnnotations(final MethodVisitor mv, -- final Context context, int v, final boolean visible) { -- int i; -- int n = b[v++] & 0xFF; -- // workaround for a bug in javac (javac compiler generates a parameter -- // annotation array whose size is equal to the number of parameters in -- // the Java source file, while it should generate an array whose size is -- // equal to the number of parameters in the method descriptor - which -- // includes the synthetic parameters added by the compiler). This work- -- // around supposes that the synthetic parameters are the first ones. -- int synthetics = Type.getArgumentTypes(context.desc).length - n; -- AnnotationVisitor av; -- for (i = 0; i < synthetics; ++i) { -- // virtual annotation to detect synthetic parameters in MethodWriter -- av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", false); -- if (av != null) { -- av.visitEnd(); -- } -- } -- char[] c = context.buffer; -- for (; i < n + synthetics; ++i) { -- int j = readUnsignedShort(v); -- v += 2; -- for (; j > 0; --j) { -- av = mv.visitParameterAnnotation(i, readUTF8(v, c), visible); -- v = readAnnotationValues(v + 2, c, true, av); -- } -- } -- } -- -- /** -- * Reads the values of an annotation and makes the given visitor visit them. -- * -- * @param v -- * the start offset in {@link #b b} of the values to be read -- * (including the unsigned short that gives the number of -- * values). -- * @param buf -- * buffer to be used to call {@link #readUTF8 readUTF8}, -- * {@link #readClass(int,char[]) readClass} or {@link #readConst -- * readConst}. -- * @param named -- * if the annotation values are named or not. -- * @param av -- * the visitor that must visit the values. -- * @return the end offset of the annotation values. -- */ -- private int readAnnotationValues(int v, final char[] buf, -- final boolean named, final AnnotationVisitor av) { -- int i = readUnsignedShort(v); -- v += 2; -- if (named) { -- for (; i > 0; --i) { -- v = readAnnotationValue(v + 2, buf, readUTF8(v, buf), av); -- } -- } else { -- for (; i > 0; --i) { -- v = readAnnotationValue(v, buf, null, av); -- } -- } -- if (av != null) { -- av.visitEnd(); -- } -- return v; -- } -- -- /** -- * Reads a value of an annotation and makes the given visitor visit it. -- * -- * @param v -- * the start offset in {@link #b b} of the value to be read -- * (not including the value name constant pool index). -- * @param buf -- * buffer to be used to call {@link #readUTF8 readUTF8}, -- * {@link #readClass(int,char[]) readClass} or {@link #readConst -- * readConst}. -- * @param name -- * the name of the value to be read. -- * @param av -- * the visitor that must visit the value. -- * @return the end offset of the annotation value. -- */ -- private int readAnnotationValue(int v, final char[] buf, final String name, -- final AnnotationVisitor av) { -- int i; -- if (av == null) { -- switch (b[v] & 0xFF) { -- case 'e': // enum_const_value -- return v + 5; -- case '@': // annotation_value -- return readAnnotationValues(v + 3, buf, true, null); -- case '[': // array_value -- return readAnnotationValues(v + 1, buf, false, null); -- default: -- return v + 3; -- } -- } -- switch (b[v++] & 0xFF) { -- case 'I': // pointer to CONSTANT_Integer -- case 'J': // pointer to CONSTANT_Long -- case 'F': // pointer to CONSTANT_Float -- case 'D': // pointer to CONSTANT_Double -- av.visit(name, readConst(readUnsignedShort(v), buf)); -- v += 2; -- break; -- case 'B': // pointer to CONSTANT_Byte -- av.visit(name, -- new Byte((byte) readInt(items[readUnsignedShort(v)]))); -- v += 2; -- break; -- case 'Z': // pointer to CONSTANT_Boolean -- av.visit(name, -- readInt(items[readUnsignedShort(v)]) == 0 ? Boolean.FALSE -- : Boolean.TRUE); -- v += 2; -- break; -- case 'S': // pointer to CONSTANT_Short -- av.visit(name, new Short( -- (short) readInt(items[readUnsignedShort(v)]))); -- v += 2; -- break; -- case 'C': // pointer to CONSTANT_Char -- av.visit(name, new Character( -- (char) readInt(items[readUnsignedShort(v)]))); -- v += 2; -- break; -- case 's': // pointer to CONSTANT_Utf8 -- av.visit(name, readUTF8(v, buf)); -- v += 2; -- break; -- case 'e': // enum_const_value -- av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf)); -- v += 4; -- break; -- case 'c': // class_info -- av.visit(name, Type.getType(readUTF8(v, buf))); -- v += 2; -- break; -- case '@': // annotation_value -- v = readAnnotationValues(v + 2, buf, true, -- av.visitAnnotation(name, readUTF8(v, buf))); -- break; -- case '[': // array_value -- int size = readUnsignedShort(v); -- v += 2; -- if (size == 0) { -- return readAnnotationValues(v - 2, buf, false, -- av.visitArray(name)); -- } -- switch (this.b[v++] & 0xFF) { -- case 'B': -- byte[] bv = new byte[size]; -- for (i = 0; i < size; i++) { -- bv[i] = (byte) readInt(items[readUnsignedShort(v)]); -- v += 3; -- } -- av.visit(name, bv); -- --v; -- break; -- case 'Z': -- boolean[] zv = new boolean[size]; -- for (i = 0; i < size; i++) { -- zv[i] = readInt(items[readUnsignedShort(v)]) != 0; -- v += 3; -- } -- av.visit(name, zv); -- --v; -- break; -- case 'S': -- short[] sv = new short[size]; -- for (i = 0; i < size; i++) { -- sv[i] = (short) readInt(items[readUnsignedShort(v)]); -- v += 3; -- } -- av.visit(name, sv); -- --v; -- break; -- case 'C': -- char[] cv = new char[size]; -- for (i = 0; i < size; i++) { -- cv[i] = (char) readInt(items[readUnsignedShort(v)]); -- v += 3; -- } -- av.visit(name, cv); -- --v; -- break; -- case 'I': -- int[] iv = new int[size]; -- for (i = 0; i < size; i++) { -- iv[i] = readInt(items[readUnsignedShort(v)]); -- v += 3; -- } -- av.visit(name, iv); -- --v; -- break; -- case 'J': -- long[] lv = new long[size]; -- for (i = 0; i < size; i++) { -- lv[i] = readLong(items[readUnsignedShort(v)]); -- v += 3; -- } -- av.visit(name, lv); -- --v; -- break; -- case 'F': -- float[] fv = new float[size]; -- for (i = 0; i < size; i++) { -- fv[i] = Float -- .intBitsToFloat(readInt(items[readUnsignedShort(v)])); -- v += 3; -- } -- av.visit(name, fv); -- --v; -- break; -- case 'D': -- double[] dv = new double[size]; -- for (i = 0; i < size; i++) { -- dv[i] = Double -- .longBitsToDouble(readLong(items[readUnsignedShort(v)])); -- v += 3; -- } -- av.visit(name, dv); -- --v; -- break; -- default: -- v = readAnnotationValues(v - 3, buf, false, av.visitArray(name)); -- } -- } -- return v; -- } -- -- /** -- * Computes the implicit frame of the method currently being parsed (as -- * defined in the given {@link Context}) and stores it in the given context. -- * -- * @param frame -- * information about the class being parsed. -- */ -- private void getImplicitFrame(final Context frame) { -- String desc = frame.desc; -- Object[] locals = frame.local; -- int local = 0; -- if ((frame.access & Opcodes.ACC_STATIC) == 0) { -- if ("".equals(frame.name)) { -- locals[local++] = Opcodes.UNINITIALIZED_THIS; -- } else { -- locals[local++] = readClass(header + 2, frame.buffer); -- } -- } -- int i = 1; -- loop: while (true) { -- int j = i; -- switch (desc.charAt(i++)) { -- case 'Z': -- case 'C': -- case 'B': -- case 'S': -- case 'I': -- locals[local++] = Opcodes.INTEGER; -- break; -- case 'F': -- locals[local++] = Opcodes.FLOAT; -- break; -- case 'J': -- locals[local++] = Opcodes.LONG; -- break; -- case 'D': -- locals[local++] = Opcodes.DOUBLE; -- break; -- case '[': -- while (desc.charAt(i) == '[') { -- ++i; -- } -- if (desc.charAt(i) == 'L') { -- ++i; -- while (desc.charAt(i) != ';') { -- ++i; -- } -- } -- locals[local++] = desc.substring(j, ++i); -- break; -- case 'L': -- while (desc.charAt(i) != ';') { -- ++i; -- } -- locals[local++] = desc.substring(j + 1, i++); -- break; -- default: -- break loop; -- } -- } -- frame.localCount = local; -- } -- -- /** -- * Reads a stack map frame and stores the result in the given -- * {@link Context} object. -- * -- * @param stackMap -- * the start offset of a stack map frame in the class file. -- * @param zip -- * if the stack map frame at stackMap is compressed or not. -- * @param unzip -- * if the stack map frame must be uncompressed. -- * @param frame -- * where the parsed stack map frame must be stored. -- * @return the offset of the first byte following the parsed frame. -- */ -- private int readFrame(int stackMap, boolean zip, boolean unzip, -- Context frame) { -- char[] c = frame.buffer; -- Label[] labels = frame.labels; -- int tag; -- int delta; -- if (zip) { -- tag = b[stackMap++] & 0xFF; -- } else { -- tag = MethodWriter.FULL_FRAME; -- frame.offset = -1; -- } -- frame.localDiff = 0; -- if (tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME) { -- delta = tag; -- frame.mode = Opcodes.F_SAME; -- frame.stackCount = 0; -- } else if (tag < MethodWriter.RESERVED) { -- delta = tag - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME; -- stackMap = readFrameType(frame.stack, 0, stackMap, c, labels); -- frame.mode = Opcodes.F_SAME1; -- frame.stackCount = 1; -- } else { -- delta = readUnsignedShort(stackMap); -- stackMap += 2; -- if (tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { -- stackMap = readFrameType(frame.stack, 0, stackMap, c, labels); -- frame.mode = Opcodes.F_SAME1; -- frame.stackCount = 1; -- } else if (tag >= MethodWriter.CHOP_FRAME -- && tag < MethodWriter.SAME_FRAME_EXTENDED) { -- frame.mode = Opcodes.F_CHOP; -- frame.localDiff = MethodWriter.SAME_FRAME_EXTENDED - tag; -- frame.localCount -= frame.localDiff; -- frame.stackCount = 0; -- } else if (tag == MethodWriter.SAME_FRAME_EXTENDED) { -- frame.mode = Opcodes.F_SAME; -- frame.stackCount = 0; -- } else if (tag < MethodWriter.FULL_FRAME) { -- int local = unzip ? frame.localCount : 0; -- for (int i = tag - MethodWriter.SAME_FRAME_EXTENDED; i > 0; i--) { -- stackMap = readFrameType(frame.local, local++, stackMap, c, -- labels); -- } -- frame.mode = Opcodes.F_APPEND; -- frame.localDiff = tag - MethodWriter.SAME_FRAME_EXTENDED; -- frame.localCount += frame.localDiff; -- frame.stackCount = 0; -- } else { // if (tag == FULL_FRAME) { -- frame.mode = Opcodes.F_FULL; -- int n = readUnsignedShort(stackMap); -- stackMap += 2; -- frame.localDiff = n; -- frame.localCount = n; -- for (int local = 0; n > 0; n--) { -- stackMap = readFrameType(frame.local, local++, stackMap, c, -- labels); -- } -- n = readUnsignedShort(stackMap); -- stackMap += 2; -- frame.stackCount = n; -- for (int stack = 0; n > 0; n--) { -- stackMap = readFrameType(frame.stack, stack++, stackMap, c, -- labels); -- } -- } -- } -- frame.offset += delta + 1; -- readLabel(frame.offset, labels); -- return stackMap; -- } -- -- /** -- * Reads a stack map frame type and stores it at the given index in the -- * given array. -- * -- * @param frame -- * the array where the parsed type must be stored. -- * @param index -- * the index in 'frame' where the parsed type must be stored. -- * @param v -- * the start offset of the stack map frame type to read. -- * @param buf -- * a buffer to read strings. -- * @param labels -- * the labels of the method currently being parsed, indexed by -- * their offset. If the parsed type is an Uninitialized type, a -- * new label for the corresponding NEW instruction is stored in -- * this array if it does not already exist. -- * @return the offset of the first byte after the parsed type. -- */ -- private int readFrameType(final Object[] frame, final int index, int v, -- final char[] buf, final Label[] labels) { -- int type = b[v++] & 0xFF; -- switch (type) { -- case 0: -- frame[index] = Opcodes.TOP; -- break; -- case 1: -- frame[index] = Opcodes.INTEGER; -- break; -- case 2: -- frame[index] = Opcodes.FLOAT; -- break; -- case 3: -- frame[index] = Opcodes.DOUBLE; -- break; -- case 4: -- frame[index] = Opcodes.LONG; -- break; -- case 5: -- frame[index] = Opcodes.NULL; -- break; -- case 6: -- frame[index] = Opcodes.UNINITIALIZED_THIS; -- break; -- case 7: // Object -- frame[index] = readClass(v, buf); -- v += 2; -- break; -- default: // Uninitialized -- frame[index] = readLabel(readUnsignedShort(v), labels); -- v += 2; -- } -- return v; -- } -- -- /** -- * Returns the label corresponding to the given offset. The default -- * implementation of this method creates a label for the given offset if it -- * has not been already created. -- * -- * @param offset -- * a bytecode offset in a method. -- * @param labels -- * the already created labels, indexed by their offset. If a -- * label already exists for offset this method must not create a -- * new one. Otherwise it must store the new label in this array. -- * @return a non null Label, which must be equal to labels[offset]. -- */ -- protected Label readLabel(int offset, Label[] labels) { -- if (labels[offset] == null) { -- labels[offset] = new Label(); -- } -- return labels[offset]; -- } -- -- /** -- * Returns the start index of the attribute_info structure of this class. -- * -- * @return the start index of the attribute_info structure of this class. -- */ -- private int getAttributes() { -- // skips the header -- int u = header + 8 + readUnsignedShort(header + 6) * 2; -- // skips fields and methods -- for (int i = readUnsignedShort(u); i > 0; --i) { -- for (int j = readUnsignedShort(u + 8); j > 0; --j) { -- u += 6 + readInt(u + 12); -- } -- u += 8; -- } -- u += 2; -- for (int i = readUnsignedShort(u); i > 0; --i) { -- for (int j = readUnsignedShort(u + 8); j > 0; --j) { -- u += 6 + readInt(u + 12); -- } -- u += 8; -- } -- // the attribute_info structure starts just after the methods -- return u + 2; -- } -- -- /** -- * Reads an attribute in {@link #b b}. -- * -- * @param attrs -- * prototypes of the attributes that must be parsed during the -- * visit of the class. Any attribute whose type is not equal to -- * the type of one the prototypes is ignored (i.e. an empty -- * {@link Attribute} instance is returned). -- * @param type -- * the type of the attribute. -- * @param off -- * index of the first byte of the attribute's content in -- * {@link #b b}. The 6 attribute header bytes, containing the -- * type and the length of the attribute, are not taken into -- * account here (they have already been read). -- * @param len -- * the length of the attribute's content. -- * @param buf -- * buffer to be used to call {@link #readUTF8 readUTF8}, -- * {@link #readClass(int,char[]) readClass} or {@link #readConst -- * readConst}. -- * @param codeOff -- * index of the first byte of code's attribute content in -- * {@link #b b}, or -1 if the attribute to be read is not a code -- * attribute. The 6 attribute header bytes, containing the type -- * and the length of the attribute, are not taken into account -- * here. -- * @param labels -- * the labels of the method's code, or null if the -- * attribute to be read is not a code attribute. -- * @return the attribute that has been read, or null to skip this -- * attribute. -- */ -- private Attribute readAttribute(final Attribute[] attrs, final String type, -- final int off, final int len, final char[] buf, final int codeOff, -- final Label[] labels) { -- for (int i = 0; i < attrs.length; ++i) { -- if (attrs[i].type.equals(type)) { -- return attrs[i].read(this, off, len, buf, codeOff, labels); -- } -- } -- return new Attribute(type).read(this, off, len, null, -1, null); -- } -- -- // ------------------------------------------------------------------------ -- // Utility methods: low level parsing -- // ------------------------------------------------------------------------ -- -- /** -- * Returns the number of constant pool items in {@link #b b}. -- * -- * @return the number of constant pool items in {@link #b b}. -- */ -- public int getItemCount() { -- return items.length; -- } -- -- /** -- * Returns the start index of the constant pool item in {@link #b b}, plus -- * one. This method is intended for {@link Attribute} sub classes, and is -- * normally not needed by class generators or adapters. -- * -- * @param item -- * the index a constant pool item. -- * @return the start index of the constant pool item in {@link #b b}, plus -- * one. -- */ -- public int getItem(final int item) { -- return items[item]; -- } -- -- /** -- * Returns the maximum length of the strings contained in the constant pool -- * of the class. -- * -- * @return the maximum length of the strings contained in the constant pool -- * of the class. -- */ -- public int getMaxStringLength() { -- return maxStringLength; -- } -- -- /** -- * Reads a byte value in {@link #b b}. This method is intended for -- * {@link Attribute} sub classes, and is normally not needed by class -- * generators or adapters. -- * -- * @param index -- * the start index of the value to be read in {@link #b b}. -- * @return the read value. -- */ -- public int readByte(final int index) { -- return b[index] & 0xFF; -- } -- -- /** -- * Reads an unsigned short value in {@link #b b}. This method is intended -- * for {@link Attribute} sub classes, and is normally not needed by class -- * generators or adapters. -- * -- * @param index -- * the start index of the value to be read in {@link #b b}. -- * @return the read value. -- */ -- public int readUnsignedShort(final int index) { -- byte[] b = this.b; -- return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); -- } -- -- /** -- * Reads a signed short value in {@link #b b}. This method is intended -- * for {@link Attribute} sub classes, and is normally not needed by class -- * generators or adapters. -- * -- * @param index -- * the start index of the value to be read in {@link #b b}. -- * @return the read value. -- */ -- public short readShort(final int index) { -- byte[] b = this.b; -- return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); -- } -- -- /** -- * Reads a signed int value in {@link #b b}. This method is intended for -- * {@link Attribute} sub classes, and is normally not needed by class -- * generators or adapters. -- * -- * @param index -- * the start index of the value to be read in {@link #b b}. -- * @return the read value. -- */ -- public int readInt(final int index) { -- byte[] b = this.b; -- return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) -- | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); -- } -- -- /** -- * Reads a signed long value in {@link #b b}. This method is intended for -- * {@link Attribute} sub classes, and is normally not needed by class -- * generators or adapters. -- * -- * @param index -- * the start index of the value to be read in {@link #b b}. -- * @return the read value. -- */ -- public long readLong(final int index) { -- long l1 = readInt(index); -- long l0 = readInt(index + 4) & 0xFFFFFFFFL; -- return (l1 << 32) | l0; -- } -- -- /** -- * Reads an UTF8 string constant pool item in {@link #b b}. This method -- * is intended for {@link Attribute} sub classes, and is normally not needed -- * by class generators or adapters. -- * -- * @param index -- * the start index of an unsigned short value in {@link #b b}, -- * whose value is the index of an UTF8 constant pool item. -- * @param buf -- * buffer to be used to read the item. This buffer must be -- * sufficiently large. It is not automatically resized. -- * @return the String corresponding to the specified UTF8 item. -- */ -- public String readUTF8(int index, final char[] buf) { -- int item = readUnsignedShort(index); -- if (index == 0 || item == 0) { -- return null; -- } -- String s = strings[item]; -- if (s != null) { -- return s; -- } -- index = items[item]; -- return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf); -- } -- -- /** -- * Reads UTF8 string in {@link #b b}. -- * -- * @param index -- * start offset of the UTF8 string to be read. -- * @param utfLen -- * length of the UTF8 string to be read. -- * @param buf -- * buffer to be used to read the string. This buffer must be -- * sufficiently large. It is not automatically resized. -- * @return the String corresponding to the specified UTF8 string. -- */ -- private String readUTF(int index, final int utfLen, final char[] buf) { -- int endIndex = index + utfLen; -- byte[] b = this.b; -- int strLen = 0; -- int c; -- int st = 0; -- char cc = 0; -- while (index < endIndex) { -- c = b[index++]; -- switch (st) { -- case 0: -- c = c & 0xFF; -- if (c < 0x80) { // 0xxxxxxx -- buf[strLen++] = (char) c; -- } else if (c < 0xE0 && c > 0xBF) { // 110x xxxx 10xx xxxx -- cc = (char) (c & 0x1F); -- st = 1; -- } else { // 1110 xxxx 10xx xxxx 10xx xxxx -- cc = (char) (c & 0x0F); -- st = 2; -- } -- break; -- -- case 1: // byte 2 of 2-byte char or byte 3 of 3-byte char -- buf[strLen++] = (char) ((cc << 6) | (c & 0x3F)); -- st = 0; -- break; -- -- case 2: // byte 2 of 3-byte char -- cc = (char) ((cc << 6) | (c & 0x3F)); -- st = 1; -- break; -- } -- } -- return new String(buf, 0, strLen); -- } -- -- /** -- * Reads a class constant pool item in {@link #b b}. This method is -- * intended for {@link Attribute} sub classes, and is normally not needed by -- * class generators or adapters. -- * -- * @param index -- * the start index of an unsigned short value in {@link #b b}, -- * whose value is the index of a class constant pool item. -- * @param buf -- * buffer to be used to read the item. This buffer must be -- * sufficiently large. It is not automatically resized. -- * @return the String corresponding to the specified class item. -- */ -- public String readClass(final int index, final char[] buf) { -- // computes the start index of the CONSTANT_Class item in b -- // and reads the CONSTANT_Utf8 item designated by -- // the first two bytes of this CONSTANT_Class item -- return readUTF8(items[readUnsignedShort(index)], buf); -- } -- -- /** -- * Reads a numeric or string constant pool item in {@link #b b}. This -- * method is intended for {@link Attribute} sub classes, and is normally not -- * needed by class generators or adapters. -- * -- * @param item -- * the index of a constant pool item. -- * @param buf -- * buffer to be used to read the item. This buffer must be -- * sufficiently large. It is not automatically resized. -- * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, -- * {@link String}, {@link Type} or {@link Handle} corresponding to -- * the given constant pool item. -- */ -- public Object readConst(final int item, final char[] buf) { -- int index = items[item]; -- switch (b[index - 1]) { -- case ClassWriter.INT: -- return new Integer(readInt(index)); -- case ClassWriter.FLOAT: -- return new Float(Float.intBitsToFloat(readInt(index))); -- case ClassWriter.LONG: -- return new Long(readLong(index)); -- case ClassWriter.DOUBLE: -- return new Double(Double.longBitsToDouble(readLong(index))); -- case ClassWriter.CLASS: -- return Type.getObjectType(readUTF8(index, buf)); -- case ClassWriter.STR: -- return readUTF8(index, buf); -- case ClassWriter.MTYPE: -- return Type.getMethodType(readUTF8(index, buf)); -- default: // case ClassWriter.HANDLE_BASE + [1..9]: -- int tag = readByte(index); -- int[] items = this.items; -- int cpIndex = items[readUnsignedShort(index + 1)]; -- String owner = readClass(cpIndex, buf); -- cpIndex = items[readUnsignedShort(cpIndex + 2)]; -- String name = readUTF8(cpIndex, buf); -- String desc = readUTF8(cpIndex + 2, buf); -- return new Handle(tag, owner, name, desc); -- } -- } --} -diff -Nru mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/ClassVisitor.java mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/ClassVisitor.java ---- mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/ClassVisitor.java 2015-08-03 15:38:02.000000000 +0200 -+++ mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/ClassVisitor.java 1970-01-01 01:00:00.000000000 +0100 -@@ -1,320 +0,0 @@ --/*** -- * 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.mvel2.asm; -- --/** -- * A visitor to visit a Java class. The methods of this class must be called in -- * the following order: visit [ visitSource ] [ -- * visitOuterClass ] ( visitAnnotation | -- * visitTypeAnnotation | visitAttribute )* ( -- * visitInnerClass | visitField | visitMethod )* -- * visitEnd. -- * -- * @author Eric Bruneton -- */ --public abstract class ClassVisitor { -- -- /** -- * The ASM API version implemented by this visitor. The value of this field -- * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -- */ -- protected final int api; -- -- /** -- * The class visitor to which this visitor must delegate method calls. May -- * be null. -- */ -- protected ClassVisitor cv; -- -- /** -- * Constructs a new {@link ClassVisitor}. -- * -- * @param api -- * the ASM API version implemented by this visitor. Must be one -- * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -- */ -- public ClassVisitor(final int api) { -- this(api, null); -- } -- -- /** -- * Constructs a new {@link ClassVisitor}. -- * -- * @param api -- * the ASM API version implemented by this visitor. Must be one -- * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -- * @param cv -- * the class visitor to which this visitor must delegate method -- * calls. May be null. -- */ -- public ClassVisitor(final int api, final ClassVisitor cv) { -- if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { -- throw new IllegalArgumentException(); -- } -- this.api = api; -- this.cv = cv; -- } -- -- /** -- * Visits the header of the class. -- * -- * @param version -- * the class version. -- * @param access -- * the class's access flags (see {@link Opcodes}). This parameter -- * also indicates if the class is deprecated. -- * @param name -- * the internal name of the class (see -- * {@link Type#getInternalName() getInternalName}). -- * @param signature -- * the signature of this class. May be null if the class -- * is not a generic one, and does not extend or implement generic -- * classes or interfaces. -- * @param superName -- * the internal of name of the super class (see -- * {@link Type#getInternalName() getInternalName}). For -- * interfaces, the super class is {@link Object}. May be -- * null, but only for the {@link Object} class. -- * @param interfaces -- * the internal names of the class's interfaces (see -- * {@link Type#getInternalName() getInternalName}). May be -- * null. -- */ -- public void visit(int version, int access, String name, String signature, -- String superName, String[] interfaces) { -- if (cv != null) { -- cv.visit(version, access, name, signature, superName, interfaces); -- } -- } -- -- /** -- * Visits the source of the class. -- * -- * @param source -- * the name of the source file from which the class was compiled. -- * May be null. -- * @param debug -- * additional debug information to compute the correspondance -- * between source and compiled elements of the class. May be -- * null. -- */ -- public void visitSource(String source, String debug) { -- if (cv != null) { -- cv.visitSource(source, debug); -- } -- } -- -- /** -- * Visits the enclosing class of the class. This method must be called only -- * if the class has an enclosing class. -- * -- * @param owner -- * internal name of the enclosing class of the class. -- * @param name -- * the name of the method that contains the class, or -- * null if the class is not enclosed in a method of its -- * enclosing class. -- * @param desc -- * the descriptor of the method that contains the class, or -- * null if the class is not enclosed in a method of its -- * enclosing class. -- */ -- public void visitOuterClass(String owner, String name, String desc) { -- if (cv != null) { -- cv.visitOuterClass(owner, name, desc); -- } -- } -- -- /** -- * Visits an annotation of the class. -- * -- * @param desc -- * the class descriptor of the annotation class. -- * @param visible -- * true if the annotation is visible at runtime. -- * @return a visitor to visit the annotation values, or null if -- * this visitor is not interested in visiting this annotation. -- */ -- public AnnotationVisitor visitAnnotation(String desc, boolean visible) { -- if (cv != null) { -- return cv.visitAnnotation(desc, visible); -- } -- return null; -- } -- -- /** -- * Visits an annotation on a type in the class signature. -- * -- * @param typeRef -- * a reference to the annotated type. The sort of this type -- * reference must be {@link TypeReference#CLASS_TYPE_PARAMETER -- * CLASS_TYPE_PARAMETER}, -- * {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND -- * CLASS_TYPE_PARAMETER_BOUND} or -- * {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. See -- * {@link TypeReference}. -- * @param typePath -- * the path to the annotated type argument, wildcard bound, array -- * element type, or static inner type within 'typeRef'. May be -- * null if the annotation targets 'typeRef' as a whole. -- * @param desc -- * the class descriptor of the annotation class. -- * @param visible -- * true if the annotation is visible at runtime. -- * @return a visitor to visit the annotation values, or null if -- * this visitor is not interested in visiting this annotation. -- */ -- public AnnotationVisitor visitTypeAnnotation(int typeRef, -- TypePath typePath, String desc, boolean visible) { -- if (api < Opcodes.ASM5) { -- throw new RuntimeException(); -- } -- if (cv != null) { -- return cv.visitTypeAnnotation(typeRef, typePath, desc, visible); -- } -- return null; -- } -- -- /** -- * Visits a non standard attribute of the class. -- * -- * @param attr -- * an attribute. -- */ -- public void visitAttribute(Attribute attr) { -- if (cv != null) { -- cv.visitAttribute(attr); -- } -- } -- -- /** -- * Visits information about an inner class. This inner class is not -- * necessarily a member of the class being visited. -- * -- * @param name -- * the internal name of an inner class (see -- * {@link Type#getInternalName() getInternalName}). -- * @param outerName -- * the internal name of the class to which the inner class -- * belongs (see {@link Type#getInternalName() getInternalName}). -- * May be null for not member classes. -- * @param innerName -- * the (simple) name of the inner class inside its enclosing -- * class. May be null for anonymous inner classes. -- * @param access -- * the access flags of the inner class as originally declared in -- * the enclosing class. -- */ -- public void visitInnerClass(String name, String outerName, -- String innerName, int access) { -- if (cv != null) { -- cv.visitInnerClass(name, outerName, innerName, access); -- } -- } -- -- /** -- * Visits a field of the class. -- * -- * @param access -- * the field's access flags (see {@link Opcodes}). This parameter -- * also indicates if the field is synthetic and/or deprecated. -- * @param name -- * the field's name. -- * @param desc -- * the field's descriptor (see {@link Type Type}). -- * @param signature -- * the field's signature. May be null if the field's -- * type does not use generic types. -- * @param value -- * the field's initial value. This parameter, which may be -- * null if the field does not have an initial value, -- * must be an {@link Integer}, a {@link Float}, a {@link Long}, a -- * {@link Double} or a {@link String} (for int, -- * float, long or String fields -- * respectively). This parameter is only used for static -- * fields. Its value is ignored for non static fields, which -- * must be initialized through bytecode instructions in -- * constructors or methods. -- * @return a visitor to visit field annotations and attributes, or -- * null if this class visitor is not interested in visiting -- * these annotations and attributes. -- */ -- public FieldVisitor visitField(int access, String name, String desc, -- String signature, Object value) { -- if (cv != null) { -- return cv.visitField(access, name, desc, signature, value); -- } -- return null; -- } -- -- /** -- * Visits a method of the class. This method must return a new -- * {@link MethodVisitor} instance (or null) each time it is called, -- * i.e., it should not return a previously returned visitor. -- * -- * @param access -- * the method's access flags (see {@link Opcodes}). This -- * parameter also indicates if the method is synthetic and/or -- * deprecated. -- * @param name -- * the method's name. -- * @param desc -- * the method's descriptor (see {@link Type Type}). -- * @param signature -- * the method's signature. May be null if the method -- * parameters, return type and exceptions do not use generic -- * types. -- * @param exceptions -- * the internal names of the method's exception classes (see -- * {@link Type#getInternalName() getInternalName}). May be -- * null. -- * @return an object to visit the byte code of the method, or null -- * if this class visitor is not interested in visiting the code of -- * this method. -- */ -- public MethodVisitor visitMethod(int access, String name, String desc, -- String signature, String[] exceptions) { -- if (cv != null) { -- return cv.visitMethod(access, name, desc, signature, exceptions); -- } -- return null; -- } -- -- /** -- * Visits the end of the class. This method, which is the last one to be -- * called, is used to inform the visitor that all the fields and methods of -- * the class have been visited. -- */ -- public void visitEnd() { -- if (cv != null) { -- cv.visitEnd(); -- } -- } --} -diff -Nru mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/ClassWriter.java mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/ClassWriter.java ---- mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/ClassWriter.java 2015-08-03 15:38:02.000000000 +0200 -+++ mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/ClassWriter.java 1970-01-01 01:00:00.000000000 +0100 -@@ -1,1776 +0,0 @@ --/*** -- * 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.mvel2.asm; -- --/** -- * A {@link ClassVisitor} that generates classes in bytecode form. More -- * precisely this visitor generates a byte array conforming to the Java class -- * file format. It can be used alone, to generate a Java class "from scratch", -- * or with one or more {@link ClassReader ClassReader} and adapter class visitor -- * to generate a modified class from one or more existing Java classes. -- * -- * @author Eric Bruneton -- */ --public class ClassWriter extends ClassVisitor { -- -- /** -- * Flag to automatically compute the maximum stack size and the maximum -- * number of local variables of methods. If this flag is set, then the -- * arguments of the {@link MethodVisitor#visitMaxs visitMaxs} method of the -- * {@link MethodVisitor} returned by the {@link #visitMethod visitMethod} -- * method will be ignored, and computed automatically from the signature and -- * the bytecode of each method. -- * -- * @see #ClassWriter(int) -- */ -- public static final int COMPUTE_MAXS = 1; -- -- /** -- * Flag to automatically compute the stack map frames of methods from -- * scratch. If this flag is set, then the calls to the -- * {@link MethodVisitor#visitFrame} method are ignored, and the stack map -- * frames are recomputed from the methods bytecode. The arguments of the -- * {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and -- * recomputed from the bytecode. In other words, computeFrames implies -- * computeMaxs. -- * -- * @see #ClassWriter(int) -- */ -- public static final int COMPUTE_FRAMES = 2; -- -- /** -- * Pseudo access flag to distinguish between the synthetic attribute and the -- * synthetic access flag. -- */ -- static final int ACC_SYNTHETIC_ATTRIBUTE = 0x40000; -- -- /** -- * Factor to convert from ACC_SYNTHETIC_ATTRIBUTE to Opcode.ACC_SYNTHETIC. -- */ -- static final int TO_ACC_SYNTHETIC = ACC_SYNTHETIC_ATTRIBUTE -- / Opcodes.ACC_SYNTHETIC; -- -- /** -- * The type of instructions without any argument. -- */ -- static final int NOARG_INSN = 0; -- -- /** -- * The type of instructions with an signed byte argument. -- */ -- static final int SBYTE_INSN = 1; -- -- /** -- * The type of instructions with an signed short argument. -- */ -- static final int SHORT_INSN = 2; -- -- /** -- * The type of instructions with a local variable index argument. -- */ -- static final int VAR_INSN = 3; -- -- /** -- * The type of instructions with an implicit local variable index argument. -- */ -- static final int IMPLVAR_INSN = 4; -- -- /** -- * The type of instructions with a type descriptor argument. -- */ -- static final int TYPE_INSN = 5; -- -- /** -- * The type of field and method invocations instructions. -- */ -- static final int FIELDORMETH_INSN = 6; -- -- /** -- * The type of the INVOKEINTERFACE/INVOKEDYNAMIC instruction. -- */ -- static final int ITFMETH_INSN = 7; -- -- /** -- * The type of the INVOKEDYNAMIC instruction. -- */ -- static final int INDYMETH_INSN = 8; -- -- /** -- * The type of instructions with a 2 bytes bytecode offset label. -- */ -- static final int LABEL_INSN = 9; -- -- /** -- * The type of instructions with a 4 bytes bytecode offset label. -- */ -- static final int LABELW_INSN = 10; -- -- /** -- * The type of the LDC instruction. -- */ -- static final int LDC_INSN = 11; -- -- /** -- * The type of the LDC_W and LDC2_W instructions. -- */ -- static final int LDCW_INSN = 12; -- -- /** -- * The type of the IINC instruction. -- */ -- static final int IINC_INSN = 13; -- -- /** -- * The type of the TABLESWITCH instruction. -- */ -- static final int TABL_INSN = 14; -- -- /** -- * The type of the LOOKUPSWITCH instruction. -- */ -- static final int LOOK_INSN = 15; -- -- /** -- * The type of the MULTIANEWARRAY instruction. -- */ -- static final int MANA_INSN = 16; -- -- /** -- * The type of the WIDE instruction. -- */ -- static final int WIDE_INSN = 17; -- -- /** -- * The instruction types of all JVM opcodes. -- */ -- static final byte[] TYPE; -- -- /** -- * The type of CONSTANT_Class constant pool items. -- */ -- static final int CLASS = 7; -- -- /** -- * The type of CONSTANT_Fieldref constant pool items. -- */ -- static final int FIELD = 9; -- -- /** -- * The type of CONSTANT_Methodref constant pool items. -- */ -- static final int METH = 10; -- -- /** -- * The type of CONSTANT_InterfaceMethodref constant pool items. -- */ -- static final int IMETH = 11; -- -- /** -- * The type of CONSTANT_String constant pool items. -- */ -- static final int STR = 8; -- -- /** -- * The type of CONSTANT_Integer constant pool items. -- */ -- static final int INT = 3; -- -- /** -- * The type of CONSTANT_Float constant pool items. -- */ -- static final int FLOAT = 4; -- -- /** -- * The type of CONSTANT_Long constant pool items. -- */ -- static final int LONG = 5; -- -- /** -- * The type of CONSTANT_Double constant pool items. -- */ -- static final int DOUBLE = 6; -- -- /** -- * The type of CONSTANT_NameAndType constant pool items. -- */ -- static final int NAME_TYPE = 12; -- -- /** -- * The type of CONSTANT_Utf8 constant pool items. -- */ -- static final int UTF8 = 1; -- -- /** -- * The type of CONSTANT_MethodType constant pool items. -- */ -- static final int MTYPE = 16; -- -- /** -- * The type of CONSTANT_MethodHandle constant pool items. -- */ -- static final int HANDLE = 15; -- -- /** -- * The type of CONSTANT_InvokeDynamic constant pool items. -- */ -- static final int INDY = 18; -- -- /** -- * The base value for all CONSTANT_MethodHandle constant pool items. -- * Internally, ASM store the 9 variations of CONSTANT_MethodHandle into 9 -- * different items. -- */ -- static final int HANDLE_BASE = 20; -- -- /** -- * Normal type Item stored in the ClassWriter {@link ClassWriter#typeTable}, -- * instead of the constant pool, in order to avoid clashes with normal -- * constant pool items in the ClassWriter constant pool's hash table. -- */ -- static final int TYPE_NORMAL = 30; -- -- /** -- * Uninitialized type Item stored in the ClassWriter -- * {@link ClassWriter#typeTable}, instead of the constant pool, in order to -- * avoid clashes with normal constant pool items in the ClassWriter constant -- * pool's hash table. -- */ -- static final int TYPE_UNINIT = 31; -- -- /** -- * Merged type Item stored in the ClassWriter {@link ClassWriter#typeTable}, -- * instead of the constant pool, in order to avoid clashes with normal -- * constant pool items in the ClassWriter constant pool's hash table. -- */ -- static final int TYPE_MERGED = 32; -- -- /** -- * The type of BootstrapMethods items. These items are stored in a special -- * class attribute named BootstrapMethods and not in the constant pool. -- */ -- static final int BSM = 33; -- -- /** -- * The class reader from which this class writer was constructed, if any. -- */ -- ClassReader cr; -- -- /** -- * Minor and major version numbers of the class to be generated. -- */ -- int version; -- -- /** -- * Index of the next item to be added in the constant pool. -- */ -- int index; -- -- /** -- * The constant pool of this class. -- */ -- final ByteVector pool; -- -- /** -- * The constant pool's hash table data. -- */ -- Item[] items; -- -- /** -- * The threshold of the constant pool's hash table. -- */ -- int threshold; -- -- /** -- * A reusable key used to look for items in the {@link #items} hash table. -- */ -- final Item key; -- -- /** -- * A reusable key used to look for items in the {@link #items} hash table. -- */ -- final Item key2; -- -- /** -- * A reusable key used to look for items in the {@link #items} hash table. -- */ -- final Item key3; -- -- /** -- * A reusable key used to look for items in the {@link #items} hash table. -- */ -- final Item key4; -- -- /** -- * A type table used to temporarily store internal names that will not -- * necessarily be stored in the constant pool. This type table is used by -- * the control flow and data flow analysis algorithm used to compute stack -- * map frames from scratch. This array associates to each index i -- * the Item whose index is i. All Item objects stored in this array -- * are also stored in the {@link #items} hash table. These two arrays allow -- * to retrieve an Item from its index or, conversely, to get the index of an -- * Item from its value. Each Item stores an internal name in its -- * {@link Item#strVal1} field. -- */ -- Item[] typeTable; -- -- /** -- * Number of elements in the {@link #typeTable} array. -- */ -- private short typeCount; -- -- /** -- * The access flags of this class. -- */ -- private int access; -- -- /** -- * The constant pool item that contains the internal name of this class. -- */ -- private int name; -- -- /** -- * The internal name of this class. -- */ -- String thisName; -- -- /** -- * The constant pool item that contains the signature of this class. -- */ -- private int signature; -- -- /** -- * The constant pool item that contains the internal name of the super class -- * of this class. -- */ -- private int superName; -- -- /** -- * Number of interfaces implemented or extended by this class or interface. -- */ -- private int interfaceCount; -- -- /** -- * The interfaces implemented or extended by this class or interface. More -- * precisely, this array contains the indexes of the constant pool items -- * that contain the internal names of these interfaces. -- */ -- private int[] interfaces; -- -- /** -- * The index of the constant pool item that contains the name of the source -- * file from which this class was compiled. -- */ -- private int sourceFile; -- -- /** -- * The SourceDebug attribute of this class. -- */ -- private ByteVector sourceDebug; -- -- /** -- * The constant pool item that contains the name of the enclosing class of -- * this class. -- */ -- private int enclosingMethodOwner; -- -- /** -- * The constant pool item that contains the name and descriptor of the -- * enclosing method of this class. -- */ -- private int enclosingMethod; -- -- /** -- * The runtime visible annotations of this class. -- */ -- private AnnotationWriter anns; -- -- /** -- * The runtime invisible annotations of this class. -- */ -- private AnnotationWriter ianns; -- -- /** -- * The runtime visible type annotations of this class. -- */ -- private AnnotationWriter tanns; -- -- /** -- * The runtime invisible type annotations of this class. -- */ -- private AnnotationWriter itanns; -- -- /** -- * The non standard attributes of this class. -- */ -- private Attribute attrs; -- -- /** -- * The number of entries in the InnerClasses attribute. -- */ -- private int innerClassesCount; -- -- /** -- * The InnerClasses attribute. -- */ -- private ByteVector innerClasses; -- -- /** -- * The number of entries in the BootstrapMethods attribute. -- */ -- int bootstrapMethodsCount; -- -- /** -- * The BootstrapMethods attribute. -- */ -- ByteVector bootstrapMethods; -- -- /** -- * The fields of this class. These fields are stored in a linked list of -- * {@link FieldWriter} objects, linked to each other by their -- * {@link FieldWriter#fv} field. This field stores the first element of this -- * list. -- */ -- FieldWriter firstField; -- -- /** -- * The fields of this class. These fields are stored in a linked list of -- * {@link FieldWriter} objects, linked to each other by their -- * {@link FieldWriter#fv} field. This field stores the last element of this -- * list. -- */ -- FieldWriter lastField; -- -- /** -- * The methods of this class. These methods are stored in a linked list of -- * {@link MethodWriter} objects, linked to each other by their -- * {@link MethodWriter#mv} field. This field stores the first element of -- * this list. -- */ -- MethodWriter firstMethod; -- -- /** -- * The methods of this class. These methods are stored in a linked list of -- * {@link MethodWriter} objects, linked to each other by their -- * {@link MethodWriter#mv} field. This field stores the last element of this -- * list. -- */ -- MethodWriter lastMethod; -- -- /** -- * true if the maximum stack size and number of local variables -- * must be automatically computed. -- */ -- private boolean computeMaxs; -- -- /** -- * true if the stack map frames must be recomputed from scratch. -- */ -- private boolean computeFrames; -- -- /** -- * true if the stack map tables of this class are invalid. The -- * {@link MethodWriter#resizeInstructions} method cannot transform existing -- * stack map tables, and so produces potentially invalid classes when it is -- * executed. In this case the class is reread and rewritten with the -- * {@link #COMPUTE_FRAMES} option (the resizeInstructions method can resize -- * stack map tables when this option is used). -- */ -- boolean invalidFrames; -- -- // ------------------------------------------------------------------------ -- // Static initializer -- // ------------------------------------------------------------------------ -- -- /** -- * Computes the instruction types of JVM opcodes. -- */ -- static { -- int i; -- byte[] b = new byte[220]; -- String s = "AAAAAAAAAAAAAAAABCLMMDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD" -- + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" -- + "AAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJJJDOPAA" -- + "AAAAGGGGGGGHIFBFAAFFAARQJJKKJJJJJJJJJJJJJJJJJJ"; -- for (i = 0; i < b.length; ++i) { -- b[i] = (byte) (s.charAt(i) - 'A'); -- } -- TYPE = b; -- -- // code to generate the above string -- // -- // // SBYTE_INSN instructions -- // b[Constants.NEWARRAY] = SBYTE_INSN; -- // b[Constants.BIPUSH] = SBYTE_INSN; -- // -- // // SHORT_INSN instructions -- // b[Constants.SIPUSH] = SHORT_INSN; -- // -- // // (IMPL)VAR_INSN instructions -- // b[Constants.RET] = VAR_INSN; -- // for (i = Constants.ILOAD; i <= Constants.ALOAD; ++i) { -- // b[i] = VAR_INSN; -- // } -- // for (i = Constants.ISTORE; i <= Constants.ASTORE; ++i) { -- // b[i] = VAR_INSN; -- // } -- // for (i = 26; i <= 45; ++i) { // ILOAD_0 to ALOAD_3 -- // b[i] = IMPLVAR_INSN; -- // } -- // for (i = 59; i <= 78; ++i) { // ISTORE_0 to ASTORE_3 -- // b[i] = IMPLVAR_INSN; -- // } -- // -- // // TYPE_INSN instructions -- // b[Constants.NEW] = TYPE_INSN; -- // b[Constants.ANEWARRAY] = TYPE_INSN; -- // b[Constants.CHECKCAST] = TYPE_INSN; -- // b[Constants.INSTANCEOF] = TYPE_INSN; -- // -- // // (Set)FIELDORMETH_INSN instructions -- // for (i = Constants.GETSTATIC; i <= Constants.INVOKESTATIC; ++i) { -- // b[i] = FIELDORMETH_INSN; -- // } -- // b[Constants.INVOKEINTERFACE] = ITFMETH_INSN; -- // b[Constants.INVOKEDYNAMIC] = INDYMETH_INSN; -- // -- // // LABEL(W)_INSN instructions -- // for (i = Constants.IFEQ; i <= Constants.JSR; ++i) { -- // b[i] = LABEL_INSN; -- // } -- // b[Constants.IFNULL] = LABEL_INSN; -- // b[Constants.IFNONNULL] = LABEL_INSN; -- // b[200] = LABELW_INSN; // GOTO_W -- // b[201] = LABELW_INSN; // JSR_W -- // // temporary opcodes used internally by ASM - see Label and -- // MethodWriter -- // for (i = 202; i < 220; ++i) { -- // b[i] = LABEL_INSN; -- // } -- // -- // // LDC(_W) instructions -- // b[Constants.LDC] = LDC_INSN; -- // b[19] = LDCW_INSN; // LDC_W -- // b[20] = LDCW_INSN; // LDC2_W -- // -- // // special instructions -- // b[Constants.IINC] = IINC_INSN; -- // b[Constants.TABLESWITCH] = TABL_INSN; -- // b[Constants.LOOKUPSWITCH] = LOOK_INSN; -- // b[Constants.MULTIANEWARRAY] = MANA_INSN; -- // b[196] = WIDE_INSN; // WIDE -- // -- // for (i = 0; i < b.length; ++i) { -- // System.err.print((char)('A' + b[i])); -- // } -- // System.err.println(); -- } -- -- // ------------------------------------------------------------------------ -- // Constructor -- // ------------------------------------------------------------------------ -- -- /** -- * Constructs a new {@link ClassWriter} object. -- * -- * @param flags -- * option flags that can be used to modify the default behavior -- * of this class. See {@link #COMPUTE_MAXS}, -- * {@link #COMPUTE_FRAMES}. -- */ -- public ClassWriter(final int flags) { -- super(Opcodes.ASM5); -- index = 1; -- pool = new ByteVector(); -- items = new Item[256]; -- threshold = (int) (0.75d * items.length); -- key = new Item(); -- key2 = new Item(); -- key3 = new Item(); -- key4 = new Item(); -- this.computeMaxs = (flags & COMPUTE_MAXS) != 0; -- this.computeFrames = (flags & COMPUTE_FRAMES) != 0; -- } -- -- /** -- * Constructs a new {@link ClassWriter} object and enables optimizations for -- * "mostly add" bytecode transformations. These optimizations are the -- * following: -- * -- *

    -- *
  • The constant pool from the original class is copied as is in the new -- * class, which saves time. New constant pool entries will be added at the -- * end if necessary, but unused constant pool entries won't be -- * removed.
  • -- *
  • Methods that are not transformed are copied as is in the new class, -- * directly from the original class bytecode (i.e. without emitting visit -- * events for all the method instructions), which saves a lot of -- * time. Untransformed methods are detected by the fact that the -- * {@link ClassReader} receives {@link MethodVisitor} objects that come from -- * a {@link ClassWriter} (and not from any other {@link ClassVisitor} -- * instance).
  • -- *
-- * -- * @param classReader -- * the {@link ClassReader} used to read the original class. It -- * will be used to copy the entire constant pool from the -- * original class and also to copy other fragments of original -- * bytecode where applicable. -- * @param flags -- * option flags that can be used to modify the default behavior -- * of this class. These option flags do not affect methods -- * that are copied as is in the new class. This means that the -- * maximum stack size nor the stack frames will be computed for -- * these methods. See {@link #COMPUTE_MAXS}, -- * {@link #COMPUTE_FRAMES}. -- */ -- public ClassWriter(final ClassReader classReader, final int flags) { -- this(flags); -- classReader.copyPool(this); -- this.cr = classReader; -- } -- -- // ------------------------------------------------------------------------ -- // Implementation of the ClassVisitor abstract class -- // ------------------------------------------------------------------------ -- -- @Override -- public final void visit(final int version, final int access, -- final String name, final String signature, final String superName, -- final String[] interfaces) { -- this.version = version; -- this.access = access; -- this.name = newClass(name); -- thisName = name; -- if (ClassReader.SIGNATURES && signature != null) { -- this.signature = newUTF8(signature); -- } -- this.superName = superName == null ? 0 : newClass(superName); -- if (interfaces != null && interfaces.length > 0) { -- interfaceCount = interfaces.length; -- this.interfaces = new int[interfaceCount]; -- for (int i = 0; i < interfaceCount; ++i) { -- this.interfaces[i] = newClass(interfaces[i]); -- } -- } -- } -- -- @Override -- public final void visitSource(final String file, final String debug) { -- if (file != null) { -- sourceFile = newUTF8(file); -- } -- if (debug != null) { -- sourceDebug = new ByteVector().encodeUTF8(debug, 0, -- Integer.MAX_VALUE); -- } -- } -- -- @Override -- public final void visitOuterClass(final String owner, final String name, -- final String desc) { -- enclosingMethodOwner = newClass(owner); -- if (name != null && desc != null) { -- enclosingMethod = newNameType(name, desc); -- } -- } -- -- @Override -- public final AnnotationVisitor visitAnnotation(final String desc, -- final boolean visible) { -- if (!ClassReader.ANNOTATIONS) { -- return null; -- } -- ByteVector bv = new ByteVector(); -- // write type, and reserve space for values count -- bv.putShort(newUTF8(desc)).putShort(0); -- AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, 2); -- if (visible) { -- aw.next = anns; -- anns = aw; -- } else { -- aw.next = ianns; -- ianns = aw; -- } -- return aw; -- } -- -- @Override -- public final AnnotationVisitor visitTypeAnnotation(int typeRef, -- TypePath typePath, final String desc, final boolean visible) { -- if (!ClassReader.ANNOTATIONS) { -- return null; -- } -- ByteVector bv = new ByteVector(); -- // write target_type and target_info -- AnnotationWriter.putTarget(typeRef, typePath, bv); -- // write type, and reserve space for values count -- bv.putShort(newUTF8(desc)).putShort(0); -- AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, -- bv.length - 2); -- if (visible) { -- aw.next = tanns; -- tanns = aw; -- } else { -- aw.next = itanns; -- itanns = aw; -- } -- return aw; -- } -- -- @Override -- public final void visitAttribute(final Attribute attr) { -- attr.next = attrs; -- attrs = attr; -- } -- -- @Override -- public final void visitInnerClass(final String name, -- final String outerName, final String innerName, final int access) { -- if (innerClasses == null) { -- innerClasses = new ByteVector(); -- } -- // �4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the -- // constant_pool table which represents a class or interface C that is -- // not a package member must have exactly one corresponding entry in the -- // classes array". To avoid duplicates we keep track in the intVal field -- // of the Item of each CONSTANT_Class_info entry C whether an inner -- // class entry has already been added for C (this field is unused for -- // class entries, and changing its value does not change the hashcode -- // and equality tests). If so we store the index of this inner class -- // entry (plus one) in intVal. This hack allows duplicate detection in -- // O(1) time. -- Item nameItem = newClassItem(name); -- if (nameItem.intVal == 0) { -- ++innerClassesCount; -- innerClasses.putShort(nameItem.index); -- innerClasses.putShort(outerName == null ? 0 : newClass(outerName)); -- innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName)); -- innerClasses.putShort(access); -- nameItem.intVal = innerClassesCount; -- } else { -- // Compare the inner classes entry nameItem.intVal - 1 with the -- // arguments of this method and throw an exception if there is a -- // difference? -- } -- } -- -- @Override -- public final FieldVisitor visitField(final int access, final String name, -- final String desc, final String signature, final Object value) { -- return new FieldWriter(this, access, name, desc, signature, value); -- } -- -- @Override -- public final MethodVisitor visitMethod(final int access, final String name, -- final String desc, final String signature, final String[] exceptions) { -- return new MethodWriter(this, access, name, desc, signature, -- exceptions, computeMaxs, computeFrames); -- } -- -- @Override -- public final void visitEnd() { -- } -- -- // ------------------------------------------------------------------------ -- // Other public methods -- // ------------------------------------------------------------------------ -- -- /** -- * Returns the bytecode of the class that was build with this class writer. -- * -- * @return the bytecode of the class that was build with this class writer. -- */ -- public byte[] toByteArray() { -- if (index > 0xFFFF) { -- throw new RuntimeException("Class file too large!"); -- } -- // computes the real size of the bytecode of this class -- int size = 24 + 2 * interfaceCount; -- int nbFields = 0; -- FieldWriter fb = firstField; -- while (fb != null) { -- ++nbFields; -- size += fb.getSize(); -- fb = (FieldWriter) fb.fv; -- } -- int nbMethods = 0; -- MethodWriter mb = firstMethod; -- while (mb != null) { -- ++nbMethods; -- size += mb.getSize(); -- mb = (MethodWriter) mb.mv; -- } -- int attributeCount = 0; -- if (bootstrapMethods != null) { -- // we put it as first attribute in order to improve a bit -- // ClassReader.copyBootstrapMethods -- ++attributeCount; -- size += 8 + bootstrapMethods.length; -- newUTF8("BootstrapMethods"); -- } -- if (ClassReader.SIGNATURES && signature != 0) { -- ++attributeCount; -- size += 8; -- newUTF8("Signature"); -- } -- if (sourceFile != 0) { -- ++attributeCount; -- size += 8; -- newUTF8("SourceFile"); -- } -- if (sourceDebug != null) { -- ++attributeCount; -- size += sourceDebug.length + 6; -- newUTF8("SourceDebugExtension"); -- } -- if (enclosingMethodOwner != 0) { -- ++attributeCount; -- size += 10; -- newUTF8("EnclosingMethod"); -- } -- if ((access & Opcodes.ACC_DEPRECATED) != 0) { -- ++attributeCount; -- size += 6; -- newUTF8("Deprecated"); -- } -- if ((access & Opcodes.ACC_SYNTHETIC) != 0) { -- if ((version & 0xFFFF) < Opcodes.V1_5 -- || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) { -- ++attributeCount; -- size += 6; -- newUTF8("Synthetic"); -- } -- } -- if (innerClasses != null) { -- ++attributeCount; -- size += 8 + innerClasses.length; -- newUTF8("InnerClasses"); -- } -- if (ClassReader.ANNOTATIONS && anns != null) { -- ++attributeCount; -- size += 8 + anns.getSize(); -- newUTF8("RuntimeVisibleAnnotations"); -- } -- if (ClassReader.ANNOTATIONS && ianns != null) { -- ++attributeCount; -- size += 8 + ianns.getSize(); -- newUTF8("RuntimeInvisibleAnnotations"); -- } -- if (ClassReader.ANNOTATIONS && tanns != null) { -- ++attributeCount; -- size += 8 + tanns.getSize(); -- newUTF8("RuntimeVisibleTypeAnnotations"); -- } -- if (ClassReader.ANNOTATIONS && itanns != null) { -- ++attributeCount; -- size += 8 + itanns.getSize(); -- newUTF8("RuntimeInvisibleTypeAnnotations"); -- } -- if (attrs != null) { -- attributeCount += attrs.getCount(); -- size += attrs.getSize(this, null, 0, -1, -1); -- } -- size += pool.length; -- // allocates a byte vector of this size, in order to avoid unnecessary -- // arraycopy operations in the ByteVector.enlarge() method -- ByteVector out = new ByteVector(size); -- out.putInt(0xCAFEBABE).putInt(version); -- out.putShort(index).putByteArray(pool.data, 0, pool.length); -- int mask = Opcodes.ACC_DEPRECATED | ACC_SYNTHETIC_ATTRIBUTE -- | ((access & ACC_SYNTHETIC_ATTRIBUTE) / TO_ACC_SYNTHETIC); -- out.putShort(access & ~mask).putShort(name).putShort(superName); -- out.putShort(interfaceCount); -- for (int i = 0; i < interfaceCount; ++i) { -- out.putShort(interfaces[i]); -- } -- out.putShort(nbFields); -- fb = firstField; -- while (fb != null) { -- fb.put(out); -- fb = (FieldWriter) fb.fv; -- } -- out.putShort(nbMethods); -- mb = firstMethod; -- while (mb != null) { -- mb.put(out); -- mb = (MethodWriter) mb.mv; -- } -- out.putShort(attributeCount); -- if (bootstrapMethods != null) { -- out.putShort(newUTF8("BootstrapMethods")); -- out.putInt(bootstrapMethods.length + 2).putShort( -- bootstrapMethodsCount); -- out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length); -- } -- if (ClassReader.SIGNATURES && signature != 0) { -- out.putShort(newUTF8("Signature")).putInt(2).putShort(signature); -- } -- if (sourceFile != 0) { -- out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile); -- } -- if (sourceDebug != null) { -- int len = sourceDebug.length; -- out.putShort(newUTF8("SourceDebugExtension")).putInt(len); -- out.putByteArray(sourceDebug.data, 0, len); -- } -- if (enclosingMethodOwner != 0) { -- out.putShort(newUTF8("EnclosingMethod")).putInt(4); -- out.putShort(enclosingMethodOwner).putShort(enclosingMethod); -- } -- if ((access & Opcodes.ACC_DEPRECATED) != 0) { -- out.putShort(newUTF8("Deprecated")).putInt(0); -- } -- if ((access & Opcodes.ACC_SYNTHETIC) != 0) { -- if ((version & 0xFFFF) < Opcodes.V1_5 -- || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) { -- out.putShort(newUTF8("Synthetic")).putInt(0); -- } -- } -- if (innerClasses != null) { -- out.putShort(newUTF8("InnerClasses")); -- out.putInt(innerClasses.length + 2).putShort(innerClassesCount); -- out.putByteArray(innerClasses.data, 0, innerClasses.length); -- } -- if (ClassReader.ANNOTATIONS && anns != null) { -- out.putShort(newUTF8("RuntimeVisibleAnnotations")); -- anns.put(out); -- } -- if (ClassReader.ANNOTATIONS && ianns != null) { -- out.putShort(newUTF8("RuntimeInvisibleAnnotations")); -- ianns.put(out); -- } -- if (ClassReader.ANNOTATIONS && tanns != null) { -- out.putShort(newUTF8("RuntimeVisibleTypeAnnotations")); -- tanns.put(out); -- } -- if (ClassReader.ANNOTATIONS && itanns != null) { -- out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations")); -- itanns.put(out); -- } -- if (attrs != null) { -- attrs.put(this, null, 0, -1, -1, out); -- } -- if (invalidFrames) { -- anns = null; -- ianns = null; -- attrs = null; -- innerClassesCount = 0; -- innerClasses = null; -- bootstrapMethodsCount = 0; -- bootstrapMethods = null; -- firstField = null; -- lastField = null; -- firstMethod = null; -- lastMethod = null; -- computeMaxs = false; -- computeFrames = true; -- invalidFrames = false; -- new ClassReader(out.data).accept(this, ClassReader.SKIP_FRAMES); -- return toByteArray(); -- } -- return out.data; -- } -- -- // ------------------------------------------------------------------------ -- // Utility methods: constant pool management -- // ------------------------------------------------------------------------ -- -- /** -- * Adds a number or string constant to the constant pool of the class being -- * build. Does nothing if the constant pool already contains a similar item. -- * -- * @param cst -- * the value of the constant to be added to the constant pool. -- * This parameter must be an {@link Integer}, a {@link Float}, a -- * {@link Long}, a {@link Double}, a {@link String} or a -- * {@link Type}. -- * @return a new or already existing constant item with the given value. -- */ -- Item newConstItem(final Object cst) { -- if (cst instanceof Integer) { -- int val = ((Integer) cst).intValue(); -- return newInteger(val); -- } else if (cst instanceof Byte) { -- int val = ((Byte) cst).intValue(); -- return newInteger(val); -- } else if (cst instanceof Character) { -- int val = ((Character) cst).charValue(); -- return newInteger(val); -- } else if (cst instanceof Short) { -- int val = ((Short) cst).intValue(); -- return newInteger(val); -- } else if (cst instanceof Boolean) { -- int val = ((Boolean) cst).booleanValue() ? 1 : 0; -- return newInteger(val); -- } else if (cst instanceof Float) { -- float val = ((Float) cst).floatValue(); -- return newFloat(val); -- } else if (cst instanceof Long) { -- long val = ((Long) cst).longValue(); -- return newLong(val); -- } else if (cst instanceof Double) { -- double val = ((Double) cst).doubleValue(); -- return newDouble(val); -- } else if (cst instanceof String) { -- return newString((String) cst); -- } else if (cst instanceof Type) { -- Type t = (Type) cst; -- int s = t.getSort(); -- if (s == Type.OBJECT) { -- return newClassItem(t.getInternalName()); -- } else if (s == Type.METHOD) { -- return newMethodTypeItem(t.getDescriptor()); -- } else { // s == primitive type or array -- return newClassItem(t.getDescriptor()); -- } -- } else if (cst instanceof Handle) { -- Handle h = (Handle) cst; -- return newHandleItem(h.tag, h.owner, h.name, h.desc); -- } else { -- throw new IllegalArgumentException("value " + cst); -- } -- } -- -- /** -- * Adds a number or string constant to the constant pool of the class being -- * build. Does nothing if the constant pool already contains a similar item. -- * This method is intended for {@link Attribute} sub classes, and is -- * normally not needed by class generators or adapters. -- * -- * @param cst -- * the value of the constant to be added to the constant pool. -- * This parameter must be an {@link Integer}, a {@link Float}, a -- * {@link Long}, a {@link Double} or a {@link String}. -- * @return the index of a new or already existing constant item with the -- * given value. -- */ -- public int newConst(final Object cst) { -- return newConstItem(cst).index; -- } -- -- /** -- * Adds an UTF8 string to the constant pool of the class being build. Does -- * nothing if the constant pool already contains a similar item. This -- * method is intended for {@link Attribute} sub classes, and is normally not -- * needed by class generators or adapters. -- * -- * @param value -- * the String value. -- * @return the index of a new or already existing UTF8 item. -- */ -- public int newUTF8(final String value) { -- key.set(UTF8, value, null, null); -- Item result = get(key); -- if (result == null) { -- pool.putByte(UTF8).putUTF8(value); -- result = new Item(index++, key); -- put(result); -- } -- return result.index; -- } -- -- /** -- * Adds a class reference to the constant pool of the class being build. -- * Does nothing if the constant pool already contains a similar item. -- * This method is intended for {@link Attribute} sub classes, and is -- * normally not needed by class generators or adapters. -- * -- * @param value -- * the internal name of the class. -- * @return a new or already existing class reference item. -- */ -- Item newClassItem(final String value) { -- key2.set(CLASS, value, null, null); -- Item result = get(key2); -- if (result == null) { -- pool.put12(CLASS, newUTF8(value)); -- result = new Item(index++, key2); -- put(result); -- } -- return result; -- } -- -- /** -- * Adds a class reference to the constant pool of the class being build. -- * Does nothing if the constant pool already contains a similar item. -- * This method is intended for {@link Attribute} sub classes, and is -- * normally not needed by class generators or adapters. -- * -- * @param value -- * the internal name of the class. -- * @return the index of a new or already existing class reference item. -- */ -- public int newClass(final String value) { -- return newClassItem(value).index; -- } -- -- /** -- * Adds a method type reference to the constant pool of the class being -- * build. Does nothing if the constant pool already contains a similar item. -- * This method is intended for {@link Attribute} sub classes, and is -- * normally not needed by class generators or adapters. -- * -- * @param methodDesc -- * method descriptor of the method type. -- * @return a new or already existing method type reference item. -- */ -- Item newMethodTypeItem(final String methodDesc) { -- key2.set(MTYPE, methodDesc, null, null); -- Item result = get(key2); -- if (result == null) { -- pool.put12(MTYPE, newUTF8(methodDesc)); -- result = new Item(index++, key2); -- put(result); -- } -- return result; -- } -- -- /** -- * Adds a method type reference to the constant pool of the class being -- * build. Does nothing if the constant pool already contains a similar item. -- * This method is intended for {@link Attribute} sub classes, and is -- * normally not needed by class generators or adapters. -- * -- * @param methodDesc -- * method descriptor of the method type. -- * @return the index of a new or already existing method type reference -- * item. -- */ -- public int newMethodType(final String methodDesc) { -- return newMethodTypeItem(methodDesc).index; -- } -- -- /** -- * Adds a handle to the constant pool of the class being build. Does nothing -- * if the constant pool already contains a similar item. This method is -- * intended for {@link Attribute} sub classes, and is normally not needed by -- * class generators or adapters. -- * -- * @param tag -- * the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, -- * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, -- * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, -- * {@link Opcodes#H_INVOKESTATIC}, -- * {@link Opcodes#H_INVOKESPECIAL}, -- * {@link Opcodes#H_NEWINVOKESPECIAL} or -- * {@link Opcodes#H_INVOKEINTERFACE}. -- * @param owner -- * the internal name of the field or method owner class. -- * @param name -- * the name of the field or method. -- * @param desc -- * the descriptor of the field or method. -- * @return a new or an already existing method type reference item. -- */ -- Item newHandleItem(final int tag, final String owner, final String name, -- final String desc) { -- key4.set(HANDLE_BASE + tag, owner, name, desc); -- Item result = get(key4); -- if (result == null) { -- if (tag <= Opcodes.H_PUTSTATIC) { -- put112(HANDLE, tag, newField(owner, name, desc)); -- } else { -- put112(HANDLE, -- tag, -- newMethod(owner, name, desc, -- tag == Opcodes.H_INVOKEINTERFACE)); -- } -- result = new Item(index++, key4); -- put(result); -- } -- return result; -- } -- -- /** -- * Adds a handle to the constant pool of the class being build. Does nothing -- * if the constant pool already contains a similar item. This method is -- * intended for {@link Attribute} sub classes, and is normally not needed by -- * class generators or adapters. -- * -- * @param tag -- * the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, -- * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, -- * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, -- * {@link Opcodes#H_INVOKESTATIC}, -- * {@link Opcodes#H_INVOKESPECIAL}, -- * {@link Opcodes#H_NEWINVOKESPECIAL} or -- * {@link Opcodes#H_INVOKEINTERFACE}. -- * @param owner -- * the internal name of the field or method owner class. -- * @param name -- * the name of the field or method. -- * @param desc -- * the descriptor of the field or method. -- * @return the index of a new or already existing method type reference -- * item. -- */ -- public int newHandle(final int tag, final String owner, final String name, -- final String desc) { -- return newHandleItem(tag, owner, name, desc).index; -- } -- -- /** -- * Adds an invokedynamic reference to the constant pool of the class being -- * build. Does nothing if the constant pool already contains a similar item. -- * This method is intended for {@link Attribute} sub classes, and is -- * normally not needed by class generators or adapters. -- * -- * @param name -- * name of the invoked method. -- * @param desc -- * descriptor of the invoke method. -- * @param bsm -- * the bootstrap method. -- * @param bsmArgs -- * the bootstrap method constant arguments. -- * -- * @return a new or an already existing invokedynamic type reference item. -- */ -- Item newInvokeDynamicItem(final String name, final String desc, -- final Handle bsm, final Object... bsmArgs) { -- // cache for performance -- ByteVector bootstrapMethods = this.bootstrapMethods; -- if (bootstrapMethods == null) { -- bootstrapMethods = this.bootstrapMethods = new ByteVector(); -- } -- -- int position = bootstrapMethods.length; // record current position -- -- int hashCode = bsm.hashCode(); -- bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name, -- bsm.desc)); -- -- int argsLength = bsmArgs.length; -- bootstrapMethods.putShort(argsLength); -- -- for (int i = 0; i < argsLength; i++) { -- Object bsmArg = bsmArgs[i]; -- hashCode ^= bsmArg.hashCode(); -- bootstrapMethods.putShort(newConst(bsmArg)); -- } -- -- byte[] data = bootstrapMethods.data; -- int length = (1 + 1 + argsLength) << 1; // (bsm + argCount + arguments) -- hashCode &= 0x7FFFFFFF; -- Item result = items[hashCode % items.length]; -- loop: while (result != null) { -- if (result.type != BSM || result.hashCode != hashCode) { -- result = result.next; -- continue; -- } -- -- // because the data encode the size of the argument -- // we don't need to test if these size are equals -- int resultPosition = result.intVal; -- for (int p = 0; p < length; p++) { -- if (data[position + p] != data[resultPosition + p]) { -- result = result.next; -- continue loop; -- } -- } -- break; -- } -- -- int bootstrapMethodIndex; -- if (result != null) { -- bootstrapMethodIndex = result.index; -- bootstrapMethods.length = position; // revert to old position -- } else { -- bootstrapMethodIndex = bootstrapMethodsCount++; -- result = new Item(bootstrapMethodIndex); -- result.set(position, hashCode); -- put(result); -- } -- -- // now, create the InvokeDynamic constant -- key3.set(name, desc, bootstrapMethodIndex); -- result = get(key3); -- if (result == null) { -- put122(INDY, bootstrapMethodIndex, newNameType(name, desc)); -- result = new Item(index++, key3); -- put(result); -- } -- return result; -- } -- -- /** -- * Adds an invokedynamic reference to the constant pool of the class being -- * build. Does nothing if the constant pool already contains a similar item. -- * This method is intended for {@link Attribute} sub classes, and is -- * normally not needed by class generators or adapters. -- * -- * @param name -- * name of the invoked method. -- * @param desc -- * descriptor of the invoke method. -- * @param bsm -- * the bootstrap method. -- * @param bsmArgs -- * the bootstrap method constant arguments. -- * -- * @return the index of a new or already existing invokedynamic reference -- * item. -- */ -- public int newInvokeDynamic(final String name, final String desc, -- final Handle bsm, final Object... bsmArgs) { -- return newInvokeDynamicItem(name, desc, bsm, bsmArgs).index; -- } -- -- /** -- * Adds a field reference to the constant pool of the class being build. -- * Does nothing if the constant pool already contains a similar item. -- * -- * @param owner -- * the internal name of the field's owner class. -- * @param name -- * the field's name. -- * @param desc -- * the field's descriptor. -- * @return a new or already existing field reference item. -- */ -- Item newFieldItem(final String owner, final String name, final String desc) { -- key3.set(FIELD, owner, name, desc); -- Item result = get(key3); -- if (result == null) { -- put122(FIELD, newClass(owner), newNameType(name, desc)); -- result = new Item(index++, key3); -- put(result); -- } -- return result; -- } -- -- /** -- * Adds a field reference to the constant pool of the class being build. -- * Does nothing if the constant pool already contains a similar item. -- * This method is intended for {@link Attribute} sub classes, and is -- * normally not needed by class generators or adapters. -- * -- * @param owner -- * the internal name of the field's owner class. -- * @param name -- * the field's name. -- * @param desc -- * the field's descriptor. -- * @return the index of a new or already existing field reference item. -- */ -- public int newField(final String owner, final String name, final String desc) { -- return newFieldItem(owner, name, desc).index; -- } -- -- /** -- * Adds a method reference to the constant pool of the class being build. -- * Does nothing if the constant pool already contains a similar item. -- * -- * @param owner -- * the internal name of the method's owner class. -- * @param name -- * the method's name. -- * @param desc -- * the method's descriptor. -- * @param itf -- * true if owner is an interface. -- * @return a new or already existing method reference item. -- */ -- Item newMethodItem(final String owner, final String name, -- final String desc, final boolean itf) { -- int type = itf ? IMETH : METH; -- key3.set(type, owner, name, desc); -- Item result = get(key3); -- if (result == null) { -- put122(type, newClass(owner), newNameType(name, desc)); -- result = new Item(index++, key3); -- put(result); -- } -- return result; -- } -- -- /** -- * Adds a method reference to the constant pool of the class being build. -- * Does nothing if the constant pool already contains a similar item. -- * This method is intended for {@link Attribute} sub classes, and is -- * normally not needed by class generators or adapters. -- * -- * @param owner -- * the internal name of the method's owner class. -- * @param name -- * the method's name. -- * @param desc -- * the method's descriptor. -- * @param itf -- * true if owner is an interface. -- * @return the index of a new or already existing method reference item. -- */ -- public int newMethod(final String owner, final String name, -- final String desc, final boolean itf) { -- return newMethodItem(owner, name, desc, itf).index; -- } -- -- /** -- * Adds an integer to the constant pool of the class being build. Does -- * nothing if the constant pool already contains a similar item. -- * -- * @param value -- * the int value. -- * @return a new or already existing int item. -- */ -- Item newInteger(final int value) { -- key.set(value); -- Item result = get(key); -- if (result == null) { -- pool.putByte(INT).putInt(value); -- result = new Item(index++, key); -- put(result); -- } -- return result; -- } -- -- /** -- * Adds a float to the constant pool of the class being build. Does nothing -- * if the constant pool already contains a similar item. -- * -- * @param value -- * the float value. -- * @return a new or already existing float item. -- */ -- Item newFloat(final float value) { -- key.set(value); -- Item result = get(key); -- if (result == null) { -- pool.putByte(FLOAT).putInt(key.intVal); -- result = new Item(index++, key); -- put(result); -- } -- return result; -- } -- -- /** -- * Adds a long to the constant pool of the class being build. Does nothing -- * if the constant pool already contains a similar item. -- * -- * @param value -- * the long value. -- * @return a new or already existing long item. -- */ -- Item newLong(final long value) { -- key.set(value); -- Item result = get(key); -- if (result == null) { -- pool.putByte(LONG).putLong(value); -- result = new Item(index, key); -- index += 2; -- put(result); -- } -- return result; -- } -- -- /** -- * Adds a double to the constant pool of the class being build. Does nothing -- * if the constant pool already contains a similar item. -- * -- * @param value -- * the double value. -- * @return a new or already existing double item. -- */ -- Item newDouble(final double value) { -- key.set(value); -- Item result = get(key); -- if (result == null) { -- pool.putByte(DOUBLE).putLong(key.longVal); -- result = new Item(index, key); -- index += 2; -- put(result); -- } -- return result; -- } -- -- /** -- * Adds a string to the constant pool of the class being build. Does nothing -- * if the constant pool already contains a similar item. -- * -- * @param value -- * the String value. -- * @return a new or already existing string item. -- */ -- private Item newString(final String value) { -- key2.set(STR, value, null, null); -- Item result = get(key2); -- if (result == null) { -- pool.put12(STR, newUTF8(value)); -- result = new Item(index++, key2); -- put(result); -- } -- return result; -- } -- -- /** -- * Adds a name and type to the constant pool of the class being build. Does -- * nothing if the constant pool already contains a similar item. This -- * method is intended for {@link Attribute} sub classes, and is normally not -- * needed by class generators or adapters. -- * -- * @param name -- * a name. -- * @param desc -- * a type descriptor. -- * @return the index of a new or already existing name and type item. -- */ -- public int newNameType(final String name, final String desc) { -- return newNameTypeItem(name, desc).index; -- } -- -- /** -- * Adds a name and type to the constant pool of the class being build. Does -- * nothing if the constant pool already contains a similar item. -- * -- * @param name -- * a name. -- * @param desc -- * a type descriptor. -- * @return a new or already existing name and type item. -- */ -- Item newNameTypeItem(final String name, final String desc) { -- key2.set(NAME_TYPE, name, desc, null); -- Item result = get(key2); -- if (result == null) { -- put122(NAME_TYPE, newUTF8(name), newUTF8(desc)); -- result = new Item(index++, key2); -- put(result); -- } -- return result; -- } -- -- /** -- * Adds the given internal name to {@link #typeTable} and returns its index. -- * Does nothing if the type table already contains this internal name. -- * -- * @param type -- * the internal name to be added to the type table. -- * @return the index of this internal name in the type table. -- */ -- int addType(final String type) { -- key.set(TYPE_NORMAL, type, null, null); -- Item result = get(key); -- if (result == null) { -- result = addType(key); -- } -- return result.index; -- } -- -- /** -- * Adds the given "uninitialized" type to {@link #typeTable} and returns its -- * index. This method is used for UNINITIALIZED types, made of an internal -- * name and a bytecode offset. -- * -- * @param type -- * the internal name to be added to the type table. -- * @param offset -- * the bytecode offset of the NEW instruction that created this -- * UNINITIALIZED type value. -- * @return the index of this internal name in the type table. -- */ -- int addUninitializedType(final String type, final int offset) { -- key.type = TYPE_UNINIT; -- key.intVal = offset; -- key.strVal1 = type; -- key.hashCode = 0x7FFFFFFF & (TYPE_UNINIT + type.hashCode() + offset); -- Item result = get(key); -- if (result == null) { -- result = addType(key); -- } -- return result.index; -- } -- -- /** -- * Adds the given Item to {@link #typeTable}. -- * -- * @param item -- * the value to be added to the type table. -- * @return the added Item, which a new Item instance with the same value as -- * the given Item. -- */ -- private Item addType(final Item item) { -- ++typeCount; -- Item result = new Item(typeCount, key); -- put(result); -- if (typeTable == null) { -- typeTable = new Item[16]; -- } -- if (typeCount == typeTable.length) { -- Item[] newTable = new Item[2 * typeTable.length]; -- System.arraycopy(typeTable, 0, newTable, 0, typeTable.length); -- typeTable = newTable; -- } -- typeTable[typeCount] = result; -- return result; -- } -- -- /** -- * Returns the index of the common super type of the two given types. This -- * method calls {@link #getCommonSuperClass} and caches the result in the -- * {@link #items} hash table to speedup future calls with the same -- * parameters. -- * -- * @param type1 -- * index of an internal name in {@link #typeTable}. -- * @param type2 -- * index of an internal name in {@link #typeTable}. -- * @return the index of the common super type of the two given types. -- */ -- int getMergedType(final int type1, final int type2) { -- key2.type = TYPE_MERGED; -- key2.longVal = type1 | (((long) type2) << 32); -- key2.hashCode = 0x7FFFFFFF & (TYPE_MERGED + type1 + type2); -- Item result = get(key2); -- if (result == null) { -- String t = typeTable[type1].strVal1; -- String u = typeTable[type2].strVal1; -- key2.intVal = addType(getCommonSuperClass(t, u)); -- result = new Item((short) 0, key2); -- put(result); -- } -- return result.intVal; -- } -- -- /** -- * Returns the common super type of the two given types. The default -- * implementation of this method loads the two given classes and uses -- * the java.lang.Class methods to find the common super class. It can be -- * overridden to compute this common super type in other ways, in particular -- * without actually loading any class, or to take into account the class -- * that is currently being generated by this ClassWriter, which can of -- * course not be loaded since it is under construction. -- * -- * @param type1 -- * the internal name of a class. -- * @param type2 -- * the internal name of another class. -- * @return the internal name of the common super class of the two given -- * classes. -- */ -- protected String getCommonSuperClass(final String type1, final String type2) { -- Class c, d; -- ClassLoader classLoader = getClass().getClassLoader(); -- try { -- c = Class.forName(type1.replace('/', '.'), false, classLoader); -- d = Class.forName(type2.replace('/', '.'), false, classLoader); -- } catch (Exception e) { -- throw new RuntimeException(e.toString()); -- } -- if (c.isAssignableFrom(d)) { -- return type1; -- } -- if (d.isAssignableFrom(c)) { -- return type2; -- } -- if (c.isInterface() || d.isInterface()) { -- return "java/lang/Object"; -- } else { -- do { -- c = c.getSuperclass(); -- } while (!c.isAssignableFrom(d)); -- return c.getName().replace('.', '/'); -- } -- } -- -- /** -- * Returns the constant pool's hash table item which is equal to the given -- * item. -- * -- * @param key -- * a constant pool item. -- * @return the constant pool's hash table item which is equal to the given -- * item, or null if there is no such item. -- */ -- private Item get(final Item key) { -- Item i = items[key.hashCode % items.length]; -- while (i != null && (i.type != key.type || !key.isEqualTo(i))) { -- i = i.next; -- } -- return i; -- } -- -- /** -- * Puts the given item in the constant pool's hash table. The hash table -- * must not already contains this item. -- * -- * @param i -- * the item to be added to the constant pool's hash table. -- */ -- private void put(final Item i) { -- if (index + typeCount > threshold) { -- int ll = items.length; -- int nl = ll * 2 + 1; -- Item[] newItems = new Item[nl]; -- for (int l = ll - 1; l >= 0; --l) { -- Item j = items[l]; -- while (j != null) { -- int index = j.hashCode % newItems.length; -- Item k = j.next; -- j.next = newItems[index]; -- newItems[index] = j; -- j = k; -- } -- } -- items = newItems; -- threshold = (int) (nl * 0.75); -- } -- int index = i.hashCode % items.length; -- i.next = items[index]; -- items[index] = i; -- } -- -- /** -- * Puts one byte and two shorts into the constant pool. -- * -- * @param b -- * a byte. -- * @param s1 -- * a short. -- * @param s2 -- * another short. -- */ -- private void put122(final int b, final int s1, final int s2) { -- pool.put12(b, s1).putShort(s2); -- } -- -- /** -- * Puts two bytes and one short into the constant pool. -- * -- * @param b1 -- * a byte. -- * @param b2 -- * another byte. -- * @param s -- * a short. -- */ -- private void put112(final int b1, final int b2, final int s) { -- pool.put11(b1, b2).putShort(s); -- } --} -diff -Nru mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/commons/AdviceAdapter.java mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/commons/AdviceAdapter.java ---- mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/commons/AdviceAdapter.java 2015-08-03 15:38:02.000000000 +0200 -+++ mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/commons/AdviceAdapter.java 1970-01-01 01:00:00.000000000 +0100 -@@ -1,646 +0,0 @@ --/*** -- * 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.mvel2.asm.commons; -- --import java.util.ArrayList; --import java.util.HashMap; --import java.util.List; --import java.util.Map; -- --import org.mvel2.asm.Handle; --import org.mvel2.asm.Label; --import org.mvel2.asm.MethodVisitor; --import org.mvel2.asm.Opcodes; --import org.mvel2.asm.Type; -- --/** -- * A {@link org.mvel2.asm.MethodVisitor} to insert before, after and around -- * advices in methods and constructors. -- *

-- * The behavior for constructors is like this: -- *

    -- * -- *
  1. as long as the INVOKESPECIAL for the object initialization has not been -- * reached, every bytecode instruction is dispatched in the ctor code visitor
  2. -- * -- *
  3. when this one is reached, it is only added in the ctor code visitor and a -- * JP invoke is added
  4. -- * -- *
  5. after that, only the other code visitor receives the instructions
  6. -- * -- *
-- * -- * @author Eugene Kuleshov -- * @author Eric Bruneton -- */ --public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes { -- -- private static final Object THIS = new Object(); -- -- private static final Object OTHER = new Object(); -- -- protected int methodAccess; -- -- protected String methodDesc; -- -- private boolean constructor; -- -- private boolean superInitialized; -- -- private List stackFrame; -- -- private Map> branches; -- -- /** -- * Creates a new {@link AdviceAdapter}. -- * -- * @param api -- * the ASM API version implemented by this visitor. Must be one -- * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -- * @param mv -- * the method visitor to which this adapter delegates calls. -- * @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}). -- */ -- protected AdviceAdapter(final int api, final MethodVisitor mv, -- final int access, final String name, final String desc) { -- super(api, mv, access, name, desc); -- methodAccess = access; -- methodDesc = desc; -- constructor = "".equals(name); -- } -- -- @Override -- public void visitCode() { -- mv.visitCode(); -- if (constructor) { -- stackFrame = new ArrayList(); -- branches = new HashMap>(); -- } else { -- superInitialized = true; -- onMethodEnter(); -- } -- } -- -- @Override -- public void visitLabel(final Label label) { -- mv.visitLabel(label); -- if (constructor && branches != null) { -- List frame = branches.get(label); -- if (frame != null) { -- stackFrame = frame; -- branches.remove(label); -- } -- } -- } -- -- @Override -- public void visitInsn(final int opcode) { -- if (constructor) { -- int s; -- switch (opcode) { -- case RETURN: // empty stack -- onMethodExit(opcode); -- break; -- case IRETURN: // 1 before n/a after -- case FRETURN: // 1 before n/a after -- case ARETURN: // 1 before n/a after -- case ATHROW: // 1 before n/a after -- popValue(); -- onMethodExit(opcode); -- break; -- case LRETURN: // 2 before n/a after -- case DRETURN: // 2 before n/a after -- popValue(); -- popValue(); -- onMethodExit(opcode); -- break; -- case NOP: -- case LALOAD: // remove 2 add 2 -- case DALOAD: // remove 2 add 2 -- case LNEG: -- case DNEG: -- case FNEG: -- case INEG: -- case L2D: -- case D2L: -- case F2I: -- case I2B: -- case I2C: -- case I2S: -- case I2F: -- case ARRAYLENGTH: -- break; -- case ACONST_NULL: -- case ICONST_M1: -- case ICONST_0: -- case ICONST_1: -- case ICONST_2: -- case ICONST_3: -- case ICONST_4: -- case ICONST_5: -- case FCONST_0: -- case FCONST_1: -- case FCONST_2: -- case F2L: // 1 before 2 after -- case F2D: -- case I2L: -- case I2D: -- pushValue(OTHER); -- break; -- case LCONST_0: -- case LCONST_1: -- case DCONST_0: -- case DCONST_1: -- pushValue(OTHER); -- pushValue(OTHER); -- break; -- case IALOAD: // remove 2 add 1 -- case FALOAD: // remove 2 add 1 -- case AALOAD: // remove 2 add 1 -- case BALOAD: // remove 2 add 1 -- case CALOAD: // remove 2 add 1 -- case SALOAD: // remove 2 add 1 -- case POP: -- case IADD: -- case FADD: -- case ISUB: -- case LSHL: // 3 before 2 after -- case LSHR: // 3 before 2 after -- case LUSHR: // 3 before 2 after -- case L2I: // 2 before 1 after -- case L2F: // 2 before 1 after -- case D2I: // 2 before 1 after -- case D2F: // 2 before 1 after -- case FSUB: -- case FMUL: -- case FDIV: -- case FREM: -- case FCMPL: // 2 before 1 after -- case FCMPG: // 2 before 1 after -- case IMUL: -- case IDIV: -- case IREM: -- case ISHL: -- case ISHR: -- case IUSHR: -- case IAND: -- case IOR: -- case IXOR: -- case MONITORENTER: -- case MONITOREXIT: -- popValue(); -- break; -- case POP2: -- case LSUB: -- case LMUL: -- case LDIV: -- case LREM: -- case LADD: -- case LAND: -- case LOR: -- case LXOR: -- case DADD: -- case DMUL: -- case DSUB: -- case DDIV: -- case DREM: -- popValue(); -- popValue(); -- break; -- case IASTORE: -- case FASTORE: -- case AASTORE: -- case BASTORE: -- case CASTORE: -- case SASTORE: -- case LCMP: // 4 before 1 after -- case DCMPL: -- case DCMPG: -- popValue(); -- popValue(); -- popValue(); -- break; -- case LASTORE: -- case DASTORE: -- popValue(); -- popValue(); -- popValue(); -- popValue(); -- break; -- case DUP: -- pushValue(peekValue()); -- break; -- case DUP_X1: -- s = stackFrame.size(); -- stackFrame.add(s - 2, stackFrame.get(s - 1)); -- break; -- case DUP_X2: -- s = stackFrame.size(); -- stackFrame.add(s - 3, stackFrame.get(s - 1)); -- break; -- case DUP2: -- s = stackFrame.size(); -- stackFrame.add(s - 2, stackFrame.get(s - 1)); -- stackFrame.add(s - 2, stackFrame.get(s - 1)); -- break; -- case DUP2_X1: -- s = stackFrame.size(); -- stackFrame.add(s - 3, stackFrame.get(s - 1)); -- stackFrame.add(s - 3, stackFrame.get(s - 1)); -- break; -- case DUP2_X2: -- s = stackFrame.size(); -- stackFrame.add(s - 4, stackFrame.get(s - 1)); -- stackFrame.add(s - 4, stackFrame.get(s - 1)); -- break; -- case SWAP: -- s = stackFrame.size(); -- stackFrame.add(s - 2, stackFrame.get(s - 1)); -- stackFrame.remove(s); -- break; -- } -- } else { -- switch (opcode) { -- case RETURN: -- case IRETURN: -- case FRETURN: -- case ARETURN: -- case LRETURN: -- case DRETURN: -- case ATHROW: -- onMethodExit(opcode); -- break; -- } -- } -- mv.visitInsn(opcode); -- } -- -- @Override -- public void visitVarInsn(final int opcode, final int var) { -- super.visitVarInsn(opcode, var); -- if (constructor) { -- switch (opcode) { -- case ILOAD: -- case FLOAD: -- pushValue(OTHER); -- break; -- case LLOAD: -- case DLOAD: -- pushValue(OTHER); -- pushValue(OTHER); -- break; -- case ALOAD: -- pushValue(var == 0 ? THIS : OTHER); -- break; -- case ASTORE: -- case ISTORE: -- case FSTORE: -- popValue(); -- break; -- case LSTORE: -- case DSTORE: -- popValue(); -- popValue(); -- break; -- } -- } -- } -- -- @Override -- public void visitFieldInsn(final int opcode, final String owner, -- final String name, final String desc) { -- mv.visitFieldInsn(opcode, owner, name, desc); -- if (constructor) { -- char c = desc.charAt(0); -- boolean longOrDouble = c == 'J' || c == 'D'; -- switch (opcode) { -- case GETSTATIC: -- pushValue(OTHER); -- if (longOrDouble) { -- pushValue(OTHER); -- } -- break; -- case PUTSTATIC: -- popValue(); -- if (longOrDouble) { -- popValue(); -- } -- break; -- case PUTFIELD: -- popValue(); -- if (longOrDouble) { -- popValue(); -- popValue(); -- } -- break; -- // case GETFIELD: -- default: -- if (longOrDouble) { -- pushValue(OTHER); -- } -- } -- } -- } -- -- @Override -- public void visitIntInsn(final int opcode, final int operand) { -- mv.visitIntInsn(opcode, operand); -- if (constructor && opcode != NEWARRAY) { -- pushValue(OTHER); -- } -- } -- -- @Override -- public void visitLdcInsn(final Object cst) { -- mv.visitLdcInsn(cst); -- if (constructor) { -- pushValue(OTHER); -- if (cst instanceof Double || cst instanceof Long) { -- pushValue(OTHER); -- } -- } -- } -- -- @Override -- public void visitMultiANewArrayInsn(final String desc, final int dims) { -- mv.visitMultiANewArrayInsn(desc, dims); -- if (constructor) { -- for (int i = 0; i < dims; i++) { -- popValue(); -- } -- pushValue(OTHER); -- } -- } -- -- @Override -- public void visitTypeInsn(final int opcode, final String type) { -- mv.visitTypeInsn(opcode, type); -- // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack -- if (constructor && opcode == NEW) { -- pushValue(OTHER); -- } -- } -- -- @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); -- } -- -- @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); -- } -- -- private void doVisitMethodInsn(int opcode, final String owner, -- final String name, final String desc, final boolean itf) { -- mv.visitMethodInsn(opcode, owner, name, desc, itf); -- if (constructor) { -- Type[] types = Type.getArgumentTypes(desc); -- for (int i = 0; i < types.length; i++) { -- popValue(); -- if (types[i].getSize() == 2) { -- popValue(); -- } -- } -- switch (opcode) { -- // case INVOKESTATIC: -- // break; -- case INVOKEINTERFACE: -- case INVOKEVIRTUAL: -- popValue(); // objectref -- break; -- case INVOKESPECIAL: -- Object type = popValue(); // objectref -- if (type == THIS && !superInitialized) { -- onMethodEnter(); -- superInitialized = true; -- // once super has been initialized it is no longer -- // necessary to keep track of stack state -- constructor = false; -- } -- break; -- } -- -- Type returnType = Type.getReturnType(desc); -- if (returnType != Type.VOID_TYPE) { -- pushValue(OTHER); -- if (returnType.getSize() == 2) { -- pushValue(OTHER); -- } -- } -- } -- } -- -- @Override -- public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, -- Object... bsmArgs) { -- mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); -- if (constructor) { -- Type[] types = Type.getArgumentTypes(desc); -- for (int i = 0; i < types.length; i++) { -- popValue(); -- if (types[i].getSize() == 2) { -- popValue(); -- } -- } -- -- Type returnType = Type.getReturnType(desc); -- if (returnType != Type.VOID_TYPE) { -- pushValue(OTHER); -- if (returnType.getSize() == 2) { -- pushValue(OTHER); -- } -- } -- } -- } -- -- @Override -- public void visitJumpInsn(final int opcode, final Label label) { -- mv.visitJumpInsn(opcode, label); -- if (constructor) { -- switch (opcode) { -- case IFEQ: -- case IFNE: -- case IFLT: -- case IFGE: -- case IFGT: -- case IFLE: -- case IFNULL: -- case IFNONNULL: -- popValue(); -- break; -- case IF_ICMPEQ: -- case IF_ICMPNE: -- case IF_ICMPLT: -- case IF_ICMPGE: -- case IF_ICMPGT: -- case IF_ICMPLE: -- case IF_ACMPEQ: -- case IF_ACMPNE: -- popValue(); -- popValue(); -- break; -- case JSR: -- pushValue(OTHER); -- break; -- } -- addBranch(label); -- } -- } -- -- @Override -- public void visitLookupSwitchInsn(final Label dflt, final int[] keys, -- final Label[] labels) { -- mv.visitLookupSwitchInsn(dflt, keys, labels); -- if (constructor) { -- popValue(); -- addBranches(dflt, labels); -- } -- } -- -- @Override -- public void visitTableSwitchInsn(final int min, final int max, -- final Label dflt, final Label... labels) { -- mv.visitTableSwitchInsn(min, max, dflt, labels); -- if (constructor) { -- popValue(); -- addBranches(dflt, labels); -- } -- } -- -- @Override -- public void visitTryCatchBlock(Label start, Label end, Label handler, -- String type) { -- super.visitTryCatchBlock(start, end, handler, type); -- if (constructor && !branches.containsKey(handler)) { -- List stackFrame = new ArrayList(); -- stackFrame.add(OTHER); -- branches.put(handler, stackFrame); -- } -- } -- -- private void addBranches(final Label dflt, final Label[] labels) { -- addBranch(dflt); -- for (int i = 0; i < labels.length; i++) { -- addBranch(labels[i]); -- } -- } -- -- private void addBranch(final Label label) { -- if (branches.containsKey(label)) { -- return; -- } -- branches.put(label, new ArrayList(stackFrame)); -- } -- -- private Object popValue() { -- return stackFrame.remove(stackFrame.size() - 1); -- } -- -- private Object peekValue() { -- return stackFrame.get(stackFrame.size() - 1); -- } -- -- private void pushValue(final Object o) { -- stackFrame.add(o); -- } -- -- /** -- * Called at the beginning of the method or after super class class call in -- * the constructor.
-- *
-- * -- * Custom code can use or change all the local variables, but should not -- * change state of the stack. -- */ -- protected void onMethodEnter() { -- } -- -- /** -- * Called before explicit exit from the method using either return or throw. -- * Top element on the stack contains the return value or exception instance. -- * For example: -- * -- *
--     *   public void onMethodExit(int opcode) {
--     *     if(opcode==RETURN) {
--     *         visitInsn(ACONST_NULL);
--     *     } else if(opcode==ARETURN || opcode==ATHROW) {
--     *         dup();
--     *     } else {
--     *         if(opcode==LRETURN || opcode==DRETURN) {
--     *             dup2();
--     *         } else {
--     *             dup();
--     *         }
--     *         box(Type.getReturnType(this.methodDesc));
--     *     }
--     *     visitIntInsn(SIPUSH, opcode);
--     *     visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
--     *   }
--     * 
--     *   // an actual call back method
--     *   public static void onExit(Object param, int opcode) {
--     *     ...
--     * 
-- * -- *
-- *
-- * -- * Custom code can use or change all the local variables, but should not -- * change state of the stack. -- * -- * @param opcode -- * one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN, DRETURN -- * or ATHROW -- * -- */ -- protected void onMethodExit(int opcode) { -- } -- -- // TODO onException, onMethodCall --} -diff -Nru mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/commons/AnalyzerAdapter.java mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/commons/AnalyzerAdapter.java ---- mvel-mvel2-2.2.6.Final/src/main/java/org/mvel2/asm/commons/AnalyzerAdapter.java 2015-08-03 15:38:02.000000000 +0200 -+++ mvel-mvel2-2.2.6.Final.asm/src/main/java/org/mvel2/asm/commons/AnalyzerAdapter.java 1970-01-01 01:00:00.000000000 +0100 -@@ -1,947 +0,0 @@ --/*** -- * 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.mvel2.asm.commons; -- --import java.util.ArrayList; --import java.util.HashMap; --import java.util.List; --import java.util.Map; -- --import org.mvel2.asm.Handle; --import org.mvel2.asm.Label; --import org.mvel2.asm.MethodVisitor; --import org.mvel2.asm.Opcodes; --import org.mvel2.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.mvel2.asm.ClassReader#EXPAND_FRAMES} option. Each -- * visitX 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 before each instruction -- * by reading the value of these fields in its visitX 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 { -- -- /** -- * List 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 null for unreachable -- * instructions. -- */ -- public List locals; -- -- /** -- * List 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 null for unreachable -- * instructions. -- */ -- public List stack; -- -- /** -- * The labels that designate the next instruction to be visited. May be -- * null. -- */ -- private List