| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,121 +1,138 @@ | ||
| // 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 clojure.asm; | ||
|
|
||
| /** | ||
| * A visitor to visit a Java field. The methods of this class must be called in the following order: | ||
| * ( <tt>visitAnnotation</tt> | <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* | ||
| * <tt>visitEnd</tt>. | ||
| * | ||
| * @author Eric Bruneton | ||
| */ | ||
| public abstract class FieldVisitor { | ||
|
|
||
| /** | ||
| * The ASM API version implemented by this visitor. The value of this field must be one of {@link | ||
| * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7_EXPERIMENTAL}. | ||
| */ | ||
| protected final int api; | ||
|
|
||
| /** The field visitor to which this visitor must delegate method calls. May be null. */ | ||
| protected FieldVisitor fv; | ||
|
|
||
| /** | ||
| * Constructs a new {@link FieldVisitor}. | ||
| * | ||
| * @param api the ASM API version implemented by this visitor. Must be one of {@link | ||
| * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link | ||
| * Opcodes#ASM7_EXPERIMENTAL}. | ||
| */ | ||
| public FieldVisitor(final int api) { | ||
| this(api, null); | ||
| } | ||
|
|
||
| /** | ||
| * Constructs a new {@link FieldVisitor}. | ||
| * | ||
| * @param api the ASM API version implemented by this visitor. Must be one of {@link | ||
| * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link | ||
| * Opcodes#ASM7_EXPERIMENTAL}. | ||
| * @param fieldVisitor the field visitor to which this visitor must delegate method calls. May be | ||
| * null. | ||
| */ | ||
| public FieldVisitor(final int api, final FieldVisitor fieldVisitor) { | ||
| if (api != Opcodes.ASM6 | ||
| && api != Opcodes.ASM5 | ||
| && api != Opcodes.ASM4 | ||
| && api != Opcodes.ASM7_EXPERIMENTAL) { | ||
| throw new IllegalArgumentException(); | ||
| } | ||
| this.api = api; | ||
| this.fv = fieldVisitor; | ||
| } | ||
|
|
||
| /** | ||
| * Visits an annotation of the field. | ||
| * | ||
| * @param descriptor the class descriptor of the annotation class. | ||
| * @param visible <tt>true</tt> if the annotation is visible at runtime. | ||
| * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not | ||
| * interested in visiting this annotation. | ||
| */ | ||
| public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { | ||
| if (fv != null) { | ||
| return fv.visitAnnotation(descriptor, visible); | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| /** | ||
| * Visits an annotation on the type of the field. | ||
| * | ||
| * @param typeRef a reference to the annotated type. The sort of this type reference must be | ||
| * {@link TypeReference#FIELD}. 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 <tt>null</tt> if the annotation targets | ||
| * 'typeRef' as a whole. | ||
| * @param descriptor the class descriptor of the annotation class. | ||
| * @param visible <tt>true</tt> if the annotation is visible at runtime. | ||
| * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not | ||
| * interested in visiting this annotation. | ||
| */ | ||
| public AnnotationVisitor visitTypeAnnotation( | ||
| final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { | ||
| if (api < Opcodes.ASM5) { | ||
| throw new UnsupportedOperationException(); | ||
| } | ||
| if (fv != null) { | ||
| return fv.visitTypeAnnotation(typeRef, typePath, descriptor, visible); | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| /** | ||
| * Visits a non standard attribute of the field. | ||
| * | ||
| * @param attribute an attribute. | ||
| */ | ||
| public void visitAttribute(final Attribute attribute) { | ||
| if (fv != null) { | ||
| fv.visitAttribute(attribute); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Visits the end of the field. This method, which is the last one to be called, is used to inform | ||
| * the visitor that all the annotations and attributes of the field have been visited. | ||
| */ | ||
| public void visitEnd() { | ||
| if (fv != null) { | ||
| fv.visitEnd(); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,121 +1,198 @@ | ||
| // 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 clojure.asm; | ||
|
|
||
| /** | ||
| * Information about an exception handler. Corresponds to an element of the exception_table array of | ||
| * a Code attribute, as defined in the Java Virtual Machine Specification (JVMS). Handler instances | ||
| * can be chained together, with their {@link #nextHandler} field, to describe a full JVMS | ||
| * exception_table array. | ||
| * | ||
| * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.3">JVMS | ||
| * 4.7.3</a> | ||
| * @author Eric Bruneton | ||
| */ | ||
| final class Handler { | ||
|
|
||
| /** | ||
| * The start_pc field of this JVMS exception_table entry. Corresponds to the beginning of the | ||
| * exception handler's scope (inclusive). | ||
| */ | ||
| final Label startPc; | ||
|
|
||
| /** | ||
| * The end_pc field of this JVMS exception_table entry. Corresponds to the end of the exception | ||
| * handler's scope (exclusive). | ||
| */ | ||
| final Label endPc; | ||
|
|
||
| /** | ||
| * The handler_pc field of this JVMS exception_table entry. Corresponding to the beginning of the | ||
| * exception handler's code. | ||
| */ | ||
| final Label handlerPc; | ||
|
|
||
| /** | ||
| * The catch_type field of this JVMS exception_table entry. This is the constant pool index of the | ||
| * internal name of the type of exceptions handled by this handler, or 0 to catch any exceptions. | ||
| */ | ||
| final int catchType; | ||
|
|
||
| /** | ||
| * The internal name of the type of exceptions handled by this handler, or <tt>null</tt> to catch | ||
| * any exceptions. | ||
| */ | ||
| final String catchTypeDescriptor; | ||
|
|
||
| /** The next exception handler. */ | ||
| Handler nextHandler; | ||
|
|
||
| /** | ||
| * Constructs a new Handler. | ||
| * | ||
| * @param startPc the start_pc field of this JVMS exception_table entry. | ||
| * @param endPc the end_pc field of this JVMS exception_table entry. | ||
| * @param handlerPc the handler_pc field of this JVMS exception_table entry. | ||
| * @param catchType The catch_type field of this JVMS exception_table entry. | ||
| * @param catchTypeDescriptor The internal name of the type of exceptions handled by this handler, | ||
| * or <tt>null</tt> to catch any exceptions. | ||
| */ | ||
| Handler( | ||
| final Label startPc, | ||
| final Label endPc, | ||
| final Label handlerPc, | ||
| final int catchType, | ||
| final String catchTypeDescriptor) { | ||
| this.startPc = startPc; | ||
| this.endPc = endPc; | ||
| this.handlerPc = handlerPc; | ||
| this.catchType = catchType; | ||
| this.catchTypeDescriptor = catchTypeDescriptor; | ||
| } | ||
|
|
||
| /** | ||
| * Constructs a new Handler from the given one, with a different scope. | ||
| * | ||
| * @param handler an existing Handler. | ||
| * @param startPc the start_pc field of this JVMS exception_table entry. | ||
| * @param endPc the end_pc field of this JVMS exception_table entry. | ||
| */ | ||
| Handler(final Handler handler, final Label startPc, final Label endPc) { | ||
| this(startPc, endPc, handler.handlerPc, handler.catchType, handler.catchTypeDescriptor); | ||
| this.nextHandler = handler.nextHandler; | ||
| } | ||
|
|
||
| /** | ||
| * Removes the range between start and end from the Handler list that begins with the given | ||
| * element. | ||
| * | ||
| * @param firstHandler the beginning of a Handler list. May be <tt>null</tt>. | ||
| * @param start the start of the range to be removed. | ||
| * @param end the end of the range to be removed. Maybe <tt>null</tt>. | ||
| * @return the exception handler list with the start-end range removed. | ||
| */ | ||
| static Handler removeRange(final Handler firstHandler, final Label start, final Label end) { | ||
| if (firstHandler == null) { | ||
| return null; | ||
| } else { | ||
| firstHandler.nextHandler = removeRange(firstHandler.nextHandler, start, end); | ||
| } | ||
| int handlerStart = firstHandler.startPc.bytecodeOffset; | ||
| int handlerEnd = firstHandler.endPc.bytecodeOffset; | ||
| int rangeStart = start.bytecodeOffset; | ||
| int rangeEnd = end == null ? Integer.MAX_VALUE : end.bytecodeOffset; | ||
| // Return early if [handlerStart,handlerEnd[ and [rangeStart,rangeEnd[ don't intersect. | ||
| if (rangeStart >= handlerEnd || rangeEnd <= handlerStart) { | ||
| return firstHandler; | ||
| } | ||
| if (rangeStart <= handlerStart) { | ||
| if (rangeEnd >= handlerEnd) { | ||
| // If [handlerStart,handlerEnd[ is included in [rangeStart,rangeEnd[, remove firstHandler. | ||
| return firstHandler.nextHandler; | ||
| } else { | ||
| // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [rangeEnd,handlerEnd[ | ||
| return new Handler(firstHandler, end, firstHandler.endPc); | ||
| } | ||
| } else if (rangeEnd >= handlerEnd) { | ||
| // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [handlerStart,rangeStart[ | ||
| return new Handler(firstHandler, firstHandler.startPc, start); | ||
| } else { | ||
| // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = | ||
| // [handlerStart,rangeStart[ + [rangeEnd,handerEnd[ | ||
| firstHandler.nextHandler = new Handler(firstHandler, end, firstHandler.endPc); | ||
| return new Handler(firstHandler, firstHandler.startPc, start); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Returns the number of elements of the Handler list that begins with the given element. | ||
| * | ||
| * @param firstHandler the beginning of a Handler list. May be <tt>null</tt>. | ||
| * @return the number of elements of the Handler list that begins with 'handler'. | ||
| */ | ||
| static int getExceptionTableLength(final Handler firstHandler) { | ||
| int length = 0; | ||
| Handler handler = firstHandler; | ||
| while (handler != null) { | ||
| length++; | ||
| handler = handler.nextHandler; | ||
| } | ||
| return length; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the size in bytes of the JVMS exception_table corresponding to the Handler list that | ||
| * begins with the given element. <i>This includes the exception_table_length field.</i> | ||
| * | ||
| * @param firstHandler the beginning of a Handler list. May be <tt>null</tt>. | ||
| * @return the size in bytes of the exception_table_length and exception_table structures. | ||
| */ | ||
| static int getExceptionTableSize(final Handler firstHandler) { | ||
| return 2 + 8 * getExceptionTableLength(firstHandler); | ||
| } | ||
|
|
||
| /** | ||
| * Puts the JVMS exception_table corresponding to the Handler list that begins with the given | ||
| * element. <i>This includes the exception_table_length field.</i> | ||
| * | ||
| * @param firstHandler the beginning of a Handler list. May be <tt>null</tt>. | ||
| * @param output where the exception_table_length and exception_table structures must be put. | ||
| */ | ||
| static void putExceptionTable(final Handler firstHandler, final ByteVector output) { | ||
| output.putShort(getExceptionTableLength(firstHandler)); | ||
| Handler handler = firstHandler; | ||
| while (handler != null) { | ||
| output | ||
| .putShort(handler.startPc.bytecodeOffset) | ||
| .putShort(handler.endPc.bytecodeOffset) | ||
| .putShort(handler.handlerPc.bytecodeOffset) | ||
| .putShort(handler.catchType); | ||
| handler = handler.nextHandler; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,175 @@ | ||
| // 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 clojure.asm; | ||
|
|
||
| /** | ||
| * A visitor to visit a Java module. The methods of this class must be called in the following | ||
| * order: <tt>visitMainClass</tt> | ( <tt>visitPackage</tt> | <tt>visitRequire</tt> | | ||
| * <tt>visitExport</tt> | <tt>visitOpen</tt> | <tt>visitUse</tt> | <tt>visitProvide</tt> )* | ||
| * <tt>visitEnd</tt>. | ||
| * | ||
| * @author Remi Forax | ||
| * @author Eric Bruneton | ||
| */ | ||
| public abstract class ModuleVisitor { | ||
| /** | ||
| * The ASM API version implemented by this visitor. The value of this field must be one of {@link | ||
| * Opcodes#ASM6} or {@link Opcodes#ASM7_EXPERIMENTAL}. | ||
| */ | ||
| protected final int api; | ||
|
|
||
| /** The module visitor to which this visitor must delegate method calls. May be null. */ | ||
| protected ModuleVisitor mv; | ||
|
|
||
| /** | ||
| * Constructs a new {@link ModuleVisitor}. | ||
| * | ||
| * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM6} | ||
| * or {@link Opcodes#ASM7_EXPERIMENTAL}. | ||
| */ | ||
| public ModuleVisitor(final int api) { | ||
| this(api, null); | ||
| } | ||
|
|
||
| /** | ||
| * Constructs a new {@link ModuleVisitor}. | ||
| * | ||
| * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM6} | ||
| * or {@link Opcodes#ASM7_EXPERIMENTAL}. | ||
| * @param moduleVisitor the module visitor to which this visitor must delegate method calls. May | ||
| * be null. | ||
| */ | ||
| public ModuleVisitor(final int api, final ModuleVisitor moduleVisitor) { | ||
| if (api != Opcodes.ASM6 && api != Opcodes.ASM7_EXPERIMENTAL) { | ||
| throw new IllegalArgumentException(); | ||
| } | ||
| this.api = api; | ||
| this.mv = moduleVisitor; | ||
| } | ||
|
|
||
| /** | ||
| * Visit the main class of the current module. | ||
| * | ||
| * @param mainClass the internal name of the main class of the current module. | ||
| */ | ||
| public void visitMainClass(final String mainClass) { | ||
| if (mv != null) { | ||
| mv.visitMainClass(mainClass); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Visit a package of the current module. | ||
| * | ||
| * @param packaze the internal name of a package. | ||
| */ | ||
| public void visitPackage(final String packaze) { | ||
| if (mv != null) { | ||
| mv.visitPackage(packaze); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Visits a dependence of the current module. | ||
| * | ||
| * @param module the fully qualified name (using dots) of the dependence. | ||
| * @param access the access flag of the dependence among {@code ACC_TRANSITIVE}, {@code | ||
| * ACC_STATIC_PHASE}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}. | ||
| * @param version the module version at compile time, or <tt>null</tt>. | ||
| */ | ||
| public void visitRequire(final String module, final int access, final String version) { | ||
| if (mv != null) { | ||
| mv.visitRequire(module, access, version); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Visit an exported package of the current module. | ||
| * | ||
| * @param packaze the internal name of the exported package. | ||
| * @param access the access flag of the exported package, valid values are among {@code | ||
| * ACC_SYNTHETIC} and {@code ACC_MANDATED}. | ||
| * @param modules the fully qualified names (using dots) of the modules that can access the public | ||
| * classes of the exported package, or <tt>null</tt>. | ||
| */ | ||
| public void visitExport(final String packaze, final int access, final String... modules) { | ||
| if (mv != null) { | ||
| mv.visitExport(packaze, access, modules); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Visit an open package of the current module. | ||
| * | ||
| * @param packaze the internal name of the opened package. | ||
| * @param access the access flag of the opened package, valid values are among {@code | ||
| * ACC_SYNTHETIC} and {@code ACC_MANDATED}. | ||
| * @param modules the fully qualified names (using dots) of the modules that can use deep | ||
| * reflection to the classes of the open package, or <tt>null</tt>. | ||
| */ | ||
| public void visitOpen(final String packaze, final int access, final String... modules) { | ||
| if (mv != null) { | ||
| mv.visitOpen(packaze, access, modules); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Visit a service used by the current module. The name must be the internal name of an interface | ||
| * or a class. | ||
| * | ||
| * @param service the internal name of the service. | ||
| */ | ||
| public void visitUse(final String service) { | ||
| if (mv != null) { | ||
| mv.visitUse(service); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Visit an implementation of a service. | ||
| * | ||
| * @param service the internal name of the service. | ||
| * @param providers the internal names of the implementations of the service (there is at least | ||
| * one provider). | ||
| */ | ||
| public void visitProvide(final String service, final String... providers) { | ||
| if (mv != null) { | ||
| mv.visitProvide(service, providers); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Visits the end of the module. This method, which is the last one to be called, is used to | ||
| * inform the visitor that everything have been visited. | ||
| */ | ||
| public void visitEnd() { | ||
| if (mv != null) { | ||
| mv.visitEnd(); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,253 @@ | ||
| // 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 clojure.asm; | ||
|
|
||
| /** | ||
| * A {@link ModuleVisitor} that generates the corresponding Module, ModulePackages and | ||
| * ModuleMainClass attributes, as defined in the Java Virtual Machine Specification (JVMS). | ||
| * | ||
| * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.25">JVMS | ||
| * 4.7.25</a> | ||
| * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.26">JVMS | ||
| * 4.7.26</a> | ||
| * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.27">JVMS | ||
| * 4.7.27</a> | ||
| * @author Remi Forax | ||
| * @author Eric Bruneton | ||
| */ | ||
| final class ModuleWriter extends ModuleVisitor { | ||
|
|
||
| /** Where the constants used in this AnnotationWriter must be stored. */ | ||
| private final SymbolTable symbolTable; | ||
|
|
||
| /** The module_name_index field of the JVMS Module attribute. */ | ||
| private final int moduleNameIndex; | ||
|
|
||
| /** The module_flags field of the JVMS Module attribute. */ | ||
| private final int moduleFlags; | ||
|
|
||
| /** The module_version_index field of the JVMS Module attribute. */ | ||
| private final int moduleVersionIndex; | ||
|
|
||
| /** The requires_count field of the JVMS Module attribute. */ | ||
| private int requiresCount; | ||
|
|
||
| /** The binary content of the 'requires' array of the JVMS Module attribute. */ | ||
| private final ByteVector requires; | ||
|
|
||
| /** The exports_count field of the JVMS Module attribute. */ | ||
| private int exportsCount; | ||
|
|
||
| /** The binary content of the 'exports' array of the JVMS Module attribute. */ | ||
| private final ByteVector exports; | ||
|
|
||
| /** The opens_count field of the JVMS Module attribute. */ | ||
| private int opensCount; | ||
|
|
||
| /** The binary content of the 'opens' array of the JVMS Module attribute. */ | ||
| private final ByteVector opens; | ||
|
|
||
| /** The uses_count field of the JVMS Module attribute. */ | ||
| private int usesCount; | ||
|
|
||
| /** The binary content of the 'uses_index' array of the JVMS Module attribute. */ | ||
| private final ByteVector usesIndex; | ||
|
|
||
| /** The provides_count field of the JVMS Module attribute. */ | ||
| private int providesCount; | ||
|
|
||
| /** The binary content of the 'provides' array of the JVMS Module attribute. */ | ||
| private final ByteVector provides; | ||
|
|
||
| /** The provides_count field of the JVMS ModulePackages attribute. */ | ||
| private int packageCount; | ||
|
|
||
| /** The binary content of the 'package_index' array of the JVMS ModulePackages attribute. */ | ||
| private final ByteVector packageIndex; | ||
|
|
||
| /** The main_class_index field of the JVMS ModuleMainClass attribute, or 0. */ | ||
| private int mainClassIndex; | ||
|
|
||
| ModuleWriter(final SymbolTable symbolTable, final int name, final int access, final int version) { | ||
| super(Opcodes.ASM6); | ||
| this.symbolTable = symbolTable; | ||
| this.moduleNameIndex = name; | ||
| this.moduleFlags = access; | ||
| this.moduleVersionIndex = version; | ||
| this.requires = new ByteVector(); | ||
| this.exports = new ByteVector(); | ||
| this.opens = new ByteVector(); | ||
| this.usesIndex = new ByteVector(); | ||
| this.provides = new ByteVector(); | ||
| this.packageIndex = new ByteVector(); | ||
| } | ||
|
|
||
| @Override | ||
| public void visitMainClass(final String mainClass) { | ||
| this.mainClassIndex = symbolTable.addConstantClass(mainClass).index; | ||
| } | ||
|
|
||
| @Override | ||
| public void visitPackage(final String packaze) { | ||
| packageIndex.putShort(symbolTable.addConstantPackage(packaze).index); | ||
| packageCount++; | ||
| } | ||
|
|
||
| @Override | ||
| public void visitRequire(final String module, final int access, final String version) { | ||
| requires | ||
| .putShort(symbolTable.addConstantModule(module).index) | ||
| .putShort(access) | ||
| .putShort(version == null ? 0 : symbolTable.addConstantUtf8(version)); | ||
| requiresCount++; | ||
| } | ||
|
|
||
| @Override | ||
| public void visitExport(final String packaze, final int access, final String... modules) { | ||
| exports.putShort(symbolTable.addConstantPackage(packaze).index).putShort(access); | ||
| if (modules == null) { | ||
| exports.putShort(0); | ||
| } else { | ||
| exports.putShort(modules.length); | ||
| for (String module : modules) { | ||
| exports.putShort(symbolTable.addConstantModule(module).index); | ||
| } | ||
| } | ||
| exportsCount++; | ||
| } | ||
|
|
||
| @Override | ||
| public void visitOpen(final String packaze, final int access, final String... modules) { | ||
| opens.putShort(symbolTable.addConstantPackage(packaze).index).putShort(access); | ||
| if (modules == null) { | ||
| opens.putShort(0); | ||
| } else { | ||
| opens.putShort(modules.length); | ||
| for (String module : modules) { | ||
| opens.putShort(symbolTable.addConstantModule(module).index); | ||
| } | ||
| } | ||
| opensCount++; | ||
| } | ||
|
|
||
| @Override | ||
| public void visitUse(final String service) { | ||
| usesIndex.putShort(symbolTable.addConstantClass(service).index); | ||
| usesCount++; | ||
| } | ||
|
|
||
| @Override | ||
| public void visitProvide(final String service, final String... providers) { | ||
| provides.putShort(symbolTable.addConstantClass(service).index); | ||
| provides.putShort(providers.length); | ||
| for (String provider : providers) { | ||
| provides.putShort(symbolTable.addConstantClass(provider).index); | ||
| } | ||
| providesCount++; | ||
| } | ||
|
|
||
| @Override | ||
| public void visitEnd() { | ||
| // Nothing to do. | ||
| } | ||
|
|
||
| /** | ||
| * Returns the number of Module, ModulePackages and ModuleMainClass attributes generated by this | ||
| * ModuleWriter. | ||
| * | ||
| * @return the number of Module, ModulePackages and ModuleMainClass attributes (between 1 and 3). | ||
| */ | ||
| int getAttributeCount() { | ||
| return 1 + (packageCount > 0 ? 1 : 0) + (mainClassIndex > 0 ? 1 : 0); | ||
| } | ||
|
|
||
| /** | ||
| * Returns the size of the Module, ModulePackages and ModuleMainClass attributes generated by this | ||
| * ModuleWriter. Also add the names of these attributes in the constant pool. | ||
| * | ||
| * @return the size in bytes of the Module, ModulePackages and ModuleMainClass attributes. | ||
| */ | ||
| int computeAttributesSize() { | ||
| symbolTable.addConstantUtf8(Constants.MODULE); | ||
| // 6 attribute header bytes, 6 bytes for name, flags and version, and 5 * 2 bytes for counts. | ||
| int size = | ||
| 22 + requires.length + exports.length + opens.length + usesIndex.length + provides.length; | ||
| if (packageCount > 0) { | ||
| symbolTable.addConstantUtf8(Constants.MODULE_PACKAGES); | ||
| // 6 attribute header bytes, and 2 bytes for package_count. | ||
| size += 8 + packageIndex.length; | ||
| } | ||
| if (mainClassIndex > 0) { | ||
| symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS); | ||
| // 6 attribute header bytes, and 2 bytes for main_class_index. | ||
| size += 8; | ||
| } | ||
| return size; | ||
| } | ||
|
|
||
| /** | ||
| * Puts the Module, ModulePackages and ModuleMainClass attributes generated by this ModuleWriter | ||
| * in the given ByteVector. | ||
| * | ||
| * @param output where the attributes must be put. | ||
| */ | ||
| void putAttributes(final ByteVector output) { | ||
| // 6 bytes for name, flags and version, and 5 * 2 bytes for counts. | ||
| int moduleAttributeLength = | ||
| 16 + requires.length + exports.length + opens.length + usesIndex.length + provides.length; | ||
| output | ||
| .putShort(symbolTable.addConstantUtf8(Constants.MODULE)) | ||
| .putInt(moduleAttributeLength) | ||
| .putShort(moduleNameIndex) | ||
| .putShort(moduleFlags) | ||
| .putShort(moduleVersionIndex) | ||
| .putShort(requiresCount) | ||
| .putByteArray(requires.data, 0, requires.length) | ||
| .putShort(exportsCount) | ||
| .putByteArray(exports.data, 0, exports.length) | ||
| .putShort(opensCount) | ||
| .putByteArray(opens.data, 0, opens.length) | ||
| .putShort(usesCount) | ||
| .putByteArray(usesIndex.data, 0, usesIndex.length) | ||
| .putShort(providesCount) | ||
| .putByteArray(provides.data, 0, provides.length); | ||
| if (packageCount > 0) { | ||
| output | ||
| .putShort(symbolTable.addConstantUtf8(Constants.MODULE_PACKAGES)) | ||
| .putInt(2 + packageIndex.length) | ||
| .putShort(packageCount) | ||
| .putByteArray(packageIndex.data, 0, packageIndex.length); | ||
| } | ||
| if (mainClassIndex > 0) { | ||
| output | ||
| .putShort(symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS)) | ||
| .putInt(2) | ||
| .putShort(mainClassIndex); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,240 @@ | ||
| // 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 clojure.asm; | ||
|
|
||
| /** | ||
| * An entry of the constant pool, of the BootstrapMethods attribute, or of the (ASM specific) type | ||
| * table of a class. | ||
| * | ||
| * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.4">JVMS | ||
| * 4.4</a> | ||
| * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.23">JVMS | ||
| * 4.7.23</a> | ||
| * @author Eric Bruneton | ||
| */ | ||
| abstract class Symbol { | ||
|
|
||
| // Tag values for the constant pool entries (using the same order as in the JVMS). | ||
|
|
||
| /** The tag value of CONSTANT_Class_info JVMS structures. */ | ||
| static final int CONSTANT_CLASS_TAG = 7; | ||
|
|
||
| /** The tag value of CONSTANT_Fieldref_info JVMS structures. */ | ||
| static final int CONSTANT_FIELDREF_TAG = 9; | ||
|
|
||
| /** The tag value of CONSTANT_Methodref_info JVMS structures. */ | ||
| static final int CONSTANT_METHODREF_TAG = 10; | ||
|
|
||
| /** The tag value of CONSTANT_InterfaceMethodref_info JVMS structures. */ | ||
| static final int CONSTANT_INTERFACE_METHODREF_TAG = 11; | ||
|
|
||
| /** The tag value of CONSTANT_String_info JVMS structures. */ | ||
| static final int CONSTANT_STRING_TAG = 8; | ||
|
|
||
| /** The tag value of CONSTANT_Integer_info JVMS structures. */ | ||
| static final int CONSTANT_INTEGER_TAG = 3; | ||
|
|
||
| /** The tag value of CONSTANT_Float_info JVMS structures. */ | ||
| static final int CONSTANT_FLOAT_TAG = 4; | ||
|
|
||
| /** The tag value of CONSTANT_Long_info JVMS structures. */ | ||
| static final int CONSTANT_LONG_TAG = 5; | ||
|
|
||
| /** The tag value of CONSTANT_Double_info JVMS structures. */ | ||
| static final int CONSTANT_DOUBLE_TAG = 6; | ||
|
|
||
| /** The tag value of CONSTANT_NameAndType_info JVMS structures. */ | ||
| static final int CONSTANT_NAME_AND_TYPE_TAG = 12; | ||
|
|
||
| /** The tag value of CONSTANT_Utf8_info JVMS structures. */ | ||
| static final int CONSTANT_UTF8_TAG = 1; | ||
|
|
||
| /** The tag value of CONSTANT_MethodHandle_info JVMS structures. */ | ||
| static final int CONSTANT_METHOD_HANDLE_TAG = 15; | ||
|
|
||
| /** The tag value of CONSTANT_MethodType_info JVMS structures. */ | ||
| static final int CONSTANT_METHOD_TYPE_TAG = 16; | ||
|
|
||
| /** The tag value of CONSTANT_Dynamic_info JVMS structures. */ | ||
| static final int CONSTANT_DYNAMIC_TAG = 17; | ||
|
|
||
| /** The tag value of CONSTANT_InvokeDynamic_info JVMS structures. */ | ||
| static final int CONSTANT_INVOKE_DYNAMIC_TAG = 18; | ||
|
|
||
| /** The tag value of CONSTANT_Module_info JVMS structures. */ | ||
| static final int CONSTANT_MODULE_TAG = 19; | ||
|
|
||
| /** The tag value of CONSTANT_Package_info JVMS structures. */ | ||
| static final int CONSTANT_PACKAGE_TAG = 20; | ||
|
|
||
| // Tag values for the BootstrapMethods attribute entries (ASM specific tag). | ||
|
|
||
| /** The tag value of the BootstrapMethods attribute entries. */ | ||
| static final int BOOTSTRAP_METHOD_TAG = 64; | ||
|
|
||
| // Tag values for the type table entries (ASM specific tags). | ||
|
|
||
| /** The tag value of a normal type entry in the (ASM specific) type table of a class. */ | ||
| static final int TYPE_TAG = 128; | ||
|
|
||
| /** | ||
| * The tag value of an {@link Frame#ITEM_UNINITIALIZED} type entry in the type table of a class. | ||
| */ | ||
| static final int UNINITIALIZED_TYPE_TAG = 129; | ||
|
|
||
| /** The tag value of a merged type entry in the (ASM specific) type table of a class. */ | ||
| static final int MERGED_TYPE_TAG = 130; | ||
|
|
||
| // Instance fields. | ||
|
|
||
| /** | ||
| * The index of this symbol in the constant pool, in the BootstrapMethods attribute, or in the | ||
| * (ASM specific) type table of a class (depending on the {@link #tag} value). | ||
| */ | ||
| final int index; | ||
|
|
||
| /** | ||
| * A tag indicating the type of this symbol. Must be one of the static tag values defined in this | ||
| * class. | ||
| */ | ||
| final int tag; | ||
|
|
||
| /** | ||
| * The internal name of the owner class of this symbol. Only used for {@link | ||
| * #CONSTANT_FIELDREF_TAG}, {@link #CONSTANT_METHODREF_TAG}, {@link | ||
| * #CONSTANT_INTERFACE_METHODREF_TAG}, and {@link #CONSTANT_METHOD_HANDLE_TAG} symbols. | ||
| */ | ||
| final String owner; | ||
|
|
||
| /** | ||
| * The name of the class field or method corresponding to this symbol. Only used for {@link | ||
| * #CONSTANT_FIELDREF_TAG}, {@link #CONSTANT_METHODREF_TAG}, {@link | ||
| * #CONSTANT_INTERFACE_METHODREF_TAG}, {@link #CONSTANT_NAME_AND_TYPE_TAG}, {@link | ||
| * #CONSTANT_METHOD_HANDLE_TAG}, {@link #CONSTANT_DYNAMIC_TAG} and {@link | ||
| * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols. | ||
| */ | ||
| final String name; | ||
|
|
||
| /** | ||
| * The string value of this symbol. This is: | ||
| * | ||
| * <ul> | ||
| * <li>a field or method descriptor for {@link #CONSTANT_FIELDREF_TAG}, {@link | ||
| * #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG}, {@link | ||
| * #CONSTANT_NAME_AND_TYPE_TAG}, {@link #CONSTANT_METHOD_HANDLE_TAG}, {@link | ||
| * #CONSTANT_METHOD_TYPE_TAG}, {@link #CONSTANT_DYNAMIC_TAG} and {@link | ||
| * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols, | ||
| * <li>an arbitrary string for {@link #CONSTANT_UTF8_TAG} and {@link #CONSTANT_STRING_TAG} | ||
| * symbols, | ||
| * <li>an internal class name for {@link #CONSTANT_CLASS_TAG}, {@link #TYPE_TAG} and {@link | ||
| * #UNINITIALIZED_TYPE_TAG} symbols, | ||
| * <li><tt>null</tt> for the other types of symbol. | ||
| * </ul> | ||
| */ | ||
| final String value; | ||
|
|
||
| /** | ||
| * The numeric value of this symbol. This is: | ||
| * | ||
| * <ul> | ||
| * <li>the symbol's value for {@link #CONSTANT_INTEGER_TAG},{@link #CONSTANT_FLOAT_TAG}, {@link | ||
| * #CONSTANT_LONG_TAG}, {@link #CONSTANT_DOUBLE_TAG}, | ||
| * <li>the CONSTANT_MethodHandle_info reference_kind field value for {@link | ||
| * #CONSTANT_METHOD_HANDLE_TAG} symbols, | ||
| * <li>the CONSTANT_InvokeDynamic_info bootstrap_method_attr_index field value for {@link | ||
| * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols, | ||
| * <li>the offset of a bootstrap method in the BootstrapMethods boostrap_methods array, for | ||
| * {@link #CONSTANT_DYNAMIC_TAG} or {@link #BOOTSTRAP_METHOD_TAG} symbols, | ||
| * <li>the bytecode offset of the NEW instruction that created an {@link | ||
| * Frame#ITEM_UNINITIALIZED} type for {@link #UNINITIALIZED_TYPE_TAG} symbols, | ||
| * <li>the indices (in the class' type table) of two {@link #TYPE_TAG} source types for {@link | ||
| * #MERGED_TYPE_TAG} symbols, | ||
| * <li>0 for the other types of symbol. | ||
| * </ul> | ||
| */ | ||
| final long data; | ||
|
|
||
| /** | ||
| * Additional information about this symbol, generally computed lazily. <i>Warning: the value of | ||
| * this field is ignored when comparing Symbol instances</i> (to avoid duplicate entries in a | ||
| * SymbolTable). Therefore, this field should only contain data that can be computed from the | ||
| * other fields of this class. It contains: | ||
| * | ||
| * <ul> | ||
| * <li>the {@link Type#getArgumentsAndReturnSizes} of the symbol's method descriptor for {@link | ||
| * #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG} and {@link | ||
| * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols, | ||
| * <li>the index in the InnerClasses_attribute 'classes' array (plus one) corresponding to this | ||
| * class, for {@link #CONSTANT_CLASS_TAG} symbols, | ||
| * <li>the index (in the class' type table) of the merged type of the two source types for | ||
| * {@link #MERGED_TYPE_TAG} symbols, | ||
| * <li>0 for the other types of symbol, or if this field has not been computed yet. | ||
| * </ul> | ||
| */ | ||
| int info; | ||
|
|
||
| /** | ||
| * Constructs a new Symbol. This constructor can't be used directly because the Symbol class is | ||
| * abstract. Instead, use the factory methods of the {@link SymbolTable} class. | ||
| * | ||
| * @param index the symbol index in the constant pool, in the BootstrapMethods attribute, or in | ||
| * the (ASM specific) type table of a class (depending on 'tag'). | ||
| * @param tag the symbol type. Must be one of the static tag values defined in this class. | ||
| * @param owner The internal name of the symbol's owner class. Maybe <tt>null</tt>. | ||
| * @param name The name of the symbol's corresponding class field or method. Maybe <tt>null</tt>. | ||
| * @param value The string value of this symbol. Maybe <tt>null</tt>. | ||
| * @param data The numeric value of this symbol. | ||
| */ | ||
| Symbol( | ||
| final int index, | ||
| final int tag, | ||
| final String owner, | ||
| final String name, | ||
| final String value, | ||
| final long data) { | ||
| this.index = index; | ||
| this.tag = tag; | ||
| this.owner = owner; | ||
| this.name = name; | ||
| this.value = value; | ||
| this.data = data; | ||
| } | ||
|
|
||
| /** | ||
| * @return the result {@link Type#getArgumentsAndReturnSizes} on {@link #value} (memoized in | ||
| * {@link #info} for efficiency). This should only be used for {@link | ||
| * #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG} and {@link | ||
| * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols. | ||
| */ | ||
| int getArgumentsAndReturnSizes() { | ||
| if (info == 0) { | ||
| info = Type.getArgumentsAndReturnSizes(value); | ||
| } | ||
| return info; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,201 @@ | ||
| // 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 clojure.asm; | ||
|
|
||
| /** | ||
| * The path to a type argument, wildcard bound, array element type, or static inner type within an | ||
| * enclosing type. | ||
| * | ||
| * @author Eric Bruneton | ||
| */ | ||
| public class TypePath { | ||
|
|
||
| /** A type path step that steps into the element type of an array type. See {@link #getStep}. */ | ||
| public static final int ARRAY_ELEMENT = 0; | ||
|
|
||
| /** A type path step that steps into the nested type of a class type. See {@link #getStep}. */ | ||
| public static final int INNER_TYPE = 1; | ||
|
|
||
| /** A type path step that steps into the bound of a wildcard type. See {@link #getStep}. */ | ||
| public static final int WILDCARD_BOUND = 2; | ||
|
|
||
| /** A type path step that steps into a type argument of a generic type. See {@link #getStep}. */ | ||
| public static final int TYPE_ARGUMENT = 3; | ||
|
|
||
| /** | ||
| * The byte array where the 'type_path' structure - as defined in the Java Virtual Machine | ||
| * Specification (JVMS) - corresponding to this TypePath is stored. The first byte of the | ||
| * structure in this array is given by {@link #typePathOffset}. | ||
| * | ||
| * @see <a | ||
| * href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.2">JVMS | ||
| * 4.7.20.2</a> | ||
| */ | ||
| private final byte[] typePathContainer; | ||
|
|
||
| /** The offset of the first byte of the type_path JVMS structure in {@link #typePathContainer}. */ | ||
| private final int typePathOffset; | ||
|
|
||
| /** | ||
| * Constructs a new TypePath. | ||
| * | ||
| * @param typePathContainer a byte array containing a type_path JVMS structure. | ||
| * @param typePathOffset the offset of the first byte of the type_path structure in | ||
| * typePathContainer. | ||
| */ | ||
| TypePath(final byte[] typePathContainer, final int typePathOffset) { | ||
| this.typePathContainer = typePathContainer; | ||
| this.typePathOffset = typePathOffset; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the length of this path, i.e. its number of steps. | ||
| * | ||
| * @return the length of this path. | ||
| */ | ||
| public int getLength() { | ||
| // path_length is stored in the first byte of a type_path. | ||
| return typePathContainer[typePathOffset]; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the value of the given step of this path. | ||
| * | ||
| * @param index an index between 0 and {@link #getLength()}, exclusive. | ||
| * @return one of {@link #ARRAY_ELEMENT}, {@link #INNER_TYPE}, {@link #WILDCARD_BOUND}, or {@link | ||
| * #TYPE_ARGUMENT}. | ||
| */ | ||
| public int getStep(final int index) { | ||
| // Returns the type_path_kind of the path element of the given index. | ||
| return typePathContainer[typePathOffset + 2 * index + 1]; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the index of the type argument that the given step is stepping into. This method should | ||
| * only be used for steps whose value is {@link #TYPE_ARGUMENT}. | ||
| * | ||
| * @param index an index between 0 and {@link #getLength()}, exclusive. | ||
| * @return the index of the type argument that the given step is stepping into. | ||
| */ | ||
| public int getStepArgument(final int index) { | ||
| // Returns the type_argument_index of the path element of the given index. | ||
| return typePathContainer[typePathOffset + 2 * index + 2]; | ||
| } | ||
|
|
||
| /** | ||
| * Converts a type path in string form, in the format used by {@link #toString()}, into a TypePath | ||
| * object. | ||
| * | ||
| * @param typePath a type path in string form, in the format used by {@link #toString()}. May be | ||
| * <tt>null</tt> or empty. | ||
| * @return the corresponding TypePath object, or <tt>null</tt> if the path is empty. | ||
| */ | ||
| public static TypePath fromString(final String typePath) { | ||
| if (typePath == null || typePath.length() == 0) { | ||
| return null; | ||
| } | ||
| int typePathLength = typePath.length(); | ||
| ByteVector output = new ByteVector(typePathLength); | ||
| output.putByte(0); | ||
| int typePathIndex = 0; | ||
| while (typePathIndex < typePathLength) { | ||
| char c = typePath.charAt(typePathIndex++); | ||
| if (c == '[') { | ||
| output.put11(ARRAY_ELEMENT, 0); | ||
| } else if (c == '.') { | ||
| output.put11(INNER_TYPE, 0); | ||
| } else if (c == '*') { | ||
| output.put11(WILDCARD_BOUND, 0); | ||
| } else if (c >= '0' && c <= '9') { | ||
| int typeArg = c - '0'; | ||
| while (typePathIndex < typePathLength) { | ||
| c = typePath.charAt(typePathIndex++); | ||
| if (c >= '0' && c <= '9') { | ||
| typeArg = typeArg * 10 + c - '0'; | ||
| } else if (c == ';') { | ||
| break; | ||
| } else { | ||
| throw new IllegalArgumentException(); | ||
| } | ||
| } | ||
| output.put11(TYPE_ARGUMENT, typeArg); | ||
| } else { | ||
| throw new IllegalArgumentException(); | ||
| } | ||
| } | ||
| output.data[0] = (byte) (output.length / 2); | ||
| return new TypePath(output.data, 0); | ||
| } | ||
|
|
||
| /** | ||
| * Returns a string representation of this type path. {@link #ARRAY_ELEMENT} steps are represented | ||
| * with '[', {@link #INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND} steps with '*' and {@link | ||
| * #TYPE_ARGUMENT} steps with their type argument index in decimal form followed by ';'. | ||
| */ | ||
| @Override | ||
| public String toString() { | ||
| int length = getLength(); | ||
| StringBuilder result = new StringBuilder(length * 2); | ||
| for (int i = 0; i < length; ++i) { | ||
| switch (getStep(i)) { | ||
| case ARRAY_ELEMENT: | ||
| result.append('['); | ||
| break; | ||
| case INNER_TYPE: | ||
| result.append('.'); | ||
| break; | ||
| case WILDCARD_BOUND: | ||
| result.append('*'); | ||
| break; | ||
| case TYPE_ARGUMENT: | ||
| result.append(getStepArgument(i)).append(';'); | ||
| break; | ||
| default: | ||
| throw new AssertionError(); | ||
| } | ||
| } | ||
| return result.toString(); | ||
| } | ||
|
|
||
| /** | ||
| * Puts the type_path JVMS structure corresponding to the given TypePath into the given | ||
| * ByteVector. | ||
| * | ||
| * @param typePath a TypePath instance, or <tt>null</tt> for empty paths. | ||
| * @param output where the type path must be put. | ||
| */ | ||
| static void put(final TypePath typePath, final ByteVector output) { | ||
| if (typePath == null) { | ||
| output.putByte(0); | ||
| } else { | ||
| int length = typePath.typePathContainer[typePath.typePathOffset] * 2 + 1; | ||
| output.putByteArray(typePath.typePathContainer, typePath.typePathOffset, length); | ||
| } | ||
| } | ||
| } |