217 changes: 117 additions & 100 deletions src/jvm/clojure/asm/FieldVisitor.java
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.
*/
// 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>visitAttribute</tt> )*
* 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}.
*/
protected final int api;
/**
* 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;
/** 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}.
*/
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}.
*/
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;
}

/**
* Constructs a new {@link FieldVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}.
* @param fv
* the field visitor to which this visitor must delegate method
* calls. May be null.
*/
public FieldVisitor(final int api, final FieldVisitor fv) {
if (api != Opcodes.ASM4) {
throw new IllegalArgumentException();
}
this.api = api;
this.fv = fv;
/**
* 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 of the field.
*
* @param desc
* 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(String desc, boolean visible) {
if (fv != null) {
return fv.visitAnnotation(desc, 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 attr
* an attribute.
*/
public void visitAttribute(Attribute attr) {
if (fv != null) {
fv.visitAttribute(attr);
}
/**
* 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();
}
/**
* 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();
}
}
}
557 changes: 315 additions & 242 deletions src/jvm/clojure/asm/FieldWriter.java

Large diffs are not rendered by default.

2,702 changes: 1,358 additions & 1,344 deletions src/jvm/clojure/asm/Frame.java

Large diffs are not rendered by default.

316 changes: 169 additions & 147 deletions src/jvm/clojure/asm/Handle.java
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
// ASM: a very small and fast Java bytecode manipulation framework
// Copyright (c) 2000-2011 INRIA, France Telecom
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.

package clojure.asm;

Expand All @@ -38,130 +36,154 @@
*/
public final class Handle {

/**
* The kind of field or method designated by this Handle. Should 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}.
*/
final int tag;

/**
* The internal name of the field or method designed by this handle.
*/
final String owner;

/**
* The name of the field or method designated by this handle.
*/
final String name;

/**
* The descriptor of the field or method designated by this handle.
*/
final String desc;

/**
* Constructs a new field or method handle.
*
* @param tag
* the kind of field or method designated by 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 designed by this
* handle.
* @param name
* the name of the field or method designated by this handle.
* @param desc
* the descriptor of the field or method designated by this
* handle.
*/
public Handle(int tag, String owner, String name, String desc) {
this.tag = tag;
this.owner = owner;
this.name = name;
this.desc = desc;
}
/**
* The kind of field or method designated by this Handle. Should 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}.
*/
private final int tag;

/**
* Returns the kind of field or method designated by this handle.
*
* @return {@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}.
*/
public int getTag() {
return tag;
}
/** The internal name of the class that owns the field or method designated by this handle. */
private final String owner;

/**
* Returns the internal name of the field or method designed by this handle.
*
* @return the internal name of the field or method designed by this handle.
*/
public String getOwner() {
return owner;
}
/** The name of the field or method designated by this handle. */
private final String name;

/**
* Returns the name of the field or method designated by this handle.
*
* @return the name of the field or method designated by this handle.
*/
public String getName() {
return name;
}
/** The descriptor of the field or method designated by this handle. */
private final String descriptor;

/**
* Returns the descriptor of the field or method designated by this handle.
*
* @return the descriptor of the field or method designated by this handle.
*/
public String getDesc() {
return desc;
}
/** Whether the owner is an interface or not. */
private final boolean isInterface;

@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Handle)) {
return false;
}
Handle h = (Handle) obj;
return tag == h.tag && owner.equals(h.owner) && name.equals(h.name)
&& desc.equals(h.desc);
}
/**
* Constructs a new field or method handle.
*
* @param tag the kind of field or method designated by 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 class that owns the field or method designated by this
* handle.
* @param name the name of the field or method designated by this handle.
* @param descriptor the descriptor of the field or method designated by this handle.
* @deprecated this constructor has been superseded by {@link #Handle(int, String, String, String,
* boolean)}.
*/
@Deprecated
public Handle(final int tag, final String owner, final String name, final String descriptor) {
this(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE);
}

@Override
public int hashCode() {
return tag + owner.hashCode() * name.hashCode() * desc.hashCode();
}
/**
* Constructs a new field or method handle.
*
* @param tag the kind of field or method designated by 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 class that owns the field or method designated by this
* handle.
* @param name the name of the field or method designated by this handle.
* @param descriptor the descriptor of the field or method designated by this handle.
* @param isInterface whether the owner is an interface or not.
*/
public Handle(
final int tag,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
this.tag = tag;
this.owner = owner;
this.name = name;
this.descriptor = descriptor;
this.isInterface = isInterface;
}

/**
* Returns the kind of field or method designated by this handle.
*
* @return {@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}.
*/
public int getTag() {
return tag;
}

/**
* Returns the internal name of the class that owns the field or method designated by this handle.
*
* @return the internal name of the class that owns the field or method designated by this handle.
*/
public String getOwner() {
return owner;
}

/**
* Returns the name of the field or method designated by this handle.
*
* @return the name of the field or method designated by this handle.
*/
public String getName() {
return name;
}

/**
* Returns the descriptor of the field or method designated by this handle.
*
* @return the descriptor of the field or method designated by this handle.
*/
public String getDesc() {
return descriptor;
}

/**
* Returns the textual representation of this handle. The textual
* representation is:
*
* <pre>
* owner '.' name desc ' ' '(' tag ')'
* </pre>
*
* . As this format is unambiguous, it can be parsed if necessary.
*/
@Override
public String toString() {
return owner + '.' + name + desc + " (" + tag + ')';
/**
* Returns true if the owner of the field or method designated by this handle is an interface.
*
* @return true if the owner of the field or method designated by this handle is an interface.
*/
public boolean isInterface() {
return isInterface;
}

@Override
public boolean equals(final Object object) {
if (object == this) {
return true;
}
if (!(object instanceof Handle)) {
return false;
}
Handle handle = (Handle) object;
return tag == handle.tag
&& isInterface == handle.isInterface
&& owner.equals(handle.owner)
&& name.equals(handle.name)
&& descriptor.equals(handle.descriptor);
}

@Override
public int hashCode() {
return tag
+ (isInterface ? 64 : 0)
+ owner.hashCode() * name.hashCode() * descriptor.hashCode();
}

/**
* Returns the textual representation of this handle. The textual representation is:
*
* <ul>
* <li>for a reference to a class: owner "." name descriptor " (" tag ")",
* <li>for a reference to an interface: owner "." name descriptor " (" tag " itf)".
* </ul>
*/
@Override
public String toString() {
return owner + '.' + name + descriptor + " (" + tag + (isInterface ? " itf" : "") + ')';
}
}
289 changes: 183 additions & 106 deletions src/jvm/clojure/asm/Handler.java
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.
*/
// 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 block.
* 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
*/
class Handler {
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;

/**
* Beginning of the exception handler's scope (inclusive).
*/
Label start;
/**
* 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;

/**
* End of the exception handler's scope (exclusive).
*/
Label end;
/**
* The internal name of the type of exceptions handled by this handler, or <tt>null</tt> to catch
* any exceptions.
*/
final String catchTypeDescriptor;

/**
* Beginning of the exception handler's code.
*/
Label handler;
/** The next exception handler. */
Handler nextHandler;

/**
* Internal name of the type of exceptions handled by this handler, or
* <tt>null</tt> to catch any exceptions.
*/
String desc;
/**
* 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;
}

/**
* Constant pool index of the internal name of the type of exceptions
* handled by this handler, or 0 to catch any exceptions.
*/
int type;
/**
* 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;
}

/**
* Next exception handler block info.
*/
Handler next;
/**
* 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);
}

/**
* Removes the range between start and end from the given exception
* handlers.
*
* @param h
* an exception handler list.
* @param start
* the start of the range to be removed.
* @param end
* the end of the range to be removed. Maybe null.
* @return the exception handler list with the start-end range removed.
*/
static Handler remove(Handler h, Label start, Label end) {
if (h == null) {
return null;
} else {
h.next = remove(h.next, start, end);
}
int hstart = h.start.position;
int hend = h.end.position;
int s = start.position;
int e = end == null ? Integer.MAX_VALUE : end.position;
// if [hstart,hend[ and [s,e[ intervals intersect...
if (s < hend && e > hstart) {
if (s <= hstart) {
if (e >= hend) {
// [hstart,hend[ fully included in [s,e[, h removed
h = h.next;
} else {
// [hstart,hend[ minus [s,e[ = [e,hend[
h.start = end;
}
} else if (e >= hend) {
// [hstart,hend[ minus [s,e[ = [hstart,s[
h.end = start;
} else {
// [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[
Handler g = new Handler();
g.start = end;
g.end = h.end;
g.handler = h.handler;
g.desc = h.desc;
g.type = h.type;
g.next = h.next;
h.end = start;
h.next = g;
}
}
return h;
/**
* 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;
}
}
}
311 changes: 0 additions & 311 deletions src/jvm/clojure/asm/Item.java

This file was deleted.

1,135 changes: 598 additions & 537 deletions src/jvm/clojure/asm/Label.java

Large diffs are not rendered by default.

1,428 changes: 776 additions & 652 deletions src/jvm/clojure/asm/MethodVisitor.java

Large diffs are not rendered by default.

4,990 changes: 2,359 additions & 2,631 deletions src/jvm/clojure/asm/MethodWriter.java

Large diffs are not rendered by default.

175 changes: 175 additions & 0 deletions src/jvm/clojure/asm/ModuleVisitor.java
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();
}
}
}
253 changes: 253 additions & 0 deletions src/jvm/clojure/asm/ModuleWriter.java
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);
}
}
}
643 changes: 316 additions & 327 deletions src/jvm/clojure/asm/Opcodes.java

Large diffs are not rendered by default.

240 changes: 240 additions & 0 deletions src/jvm/clojure/asm/Symbol.java
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;
}
}
1,277 changes: 1,277 additions & 0 deletions src/jvm/clojure/asm/SymbolTable.java

Large diffs are not rendered by default.

1,727 changes: 869 additions & 858 deletions src/jvm/clojure/asm/Type.java

Large diffs are not rendered by default.

201 changes: 201 additions & 0 deletions src/jvm/clojure/asm/TypePath.java
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);
}
}
}
436 changes: 436 additions & 0 deletions src/jvm/clojure/asm/TypeReference.java

Large diffs are not rendered by default.

625 changes: 0 additions & 625 deletions src/jvm/clojure/asm/commons/AdviceAdapter.java

This file was deleted.

920 changes: 0 additions & 920 deletions src/jvm/clojure/asm/commons/AnalyzerAdapter.java

This file was deleted.

217 changes: 0 additions & 217 deletions src/jvm/clojure/asm/commons/CodeSizeEvaluator.java

This file was deleted.

2,830 changes: 1,317 additions & 1,513 deletions src/jvm/clojure/asm/commons/GeneratorAdapter.java

Large diffs are not rendered by default.

1,090 changes: 0 additions & 1,090 deletions src/jvm/clojure/asm/commons/InstructionAdapter.java

This file was deleted.

Loading