// ASM: a very small and fast Java bytecode manipulation framework
// Copyright (c) 2000-2011 INRIA, France Telecom
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
package org.springframework.asm;
The constant pool entries, the BootstrapMethods attribute entries and the (ASM specific) type
table entries of a class.
Author: Eric Bruneton See Also:
/**
* The constant pool entries, the BootstrapMethods attribute entries and the (ASM specific) type
* table entries 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
*/
final class SymbolTable {
The ClassWriter to which this SymbolTable belongs. This is only used to get access to ClassWriter.getCommonSuperClass
and to serialize custom attributes with Attribute.write
. /**
* The ClassWriter to which this SymbolTable belongs. This is only used to get access to {@link
* ClassWriter#getCommonSuperClass} and to serialize custom attributes with {@link
* Attribute#write}.
*/
final ClassWriter classWriter;
The ClassReader from which this SymbolTable was constructed, or null if it was constructed from scratch. /**
* The ClassReader from which this SymbolTable was constructed, or {@literal null} if it was
* constructed from scratch.
*/
private final ClassReader sourceClassReader;
The major version number of the class to which this symbol table belongs. /** The major version number of the class to which this symbol table belongs. */
private int majorVersion;
The internal name of the class to which this symbol table belongs. /** The internal name of the class to which this symbol table belongs. */
private String className;
The total number of Entry
instances in entries
. This includes entries that are accessible (recursively) via Entry.next
. /**
* The total number of {@link Entry} instances in {@link #entries}. This includes entries that are
* accessible (recursively) via {@link Entry#next}.
*/
private int entryCount;
A hash set of all the entries in this SymbolTable (this includes the constant pool entries, the bootstrap method entries and the type table entries). Each Entry
instance is stored at the array index given by its hash code modulo the array size. If several entries must be stored at the same array index, they are linked together via their Entry.next
field. The factory methods of this class make sure that this table does not contain duplicated entries. /**
* A hash set of all the entries in this SymbolTable (this includes the constant pool entries, the
* bootstrap method entries and the type table entries). Each {@link Entry} instance is stored at
* the array index given by its hash code modulo the array size. If several entries must be stored
* at the same array index, they are linked together via their {@link Entry#next} field. The
* factory methods of this class make sure that this table does not contain duplicated entries.
*/
private Entry[] entries;
The number of constant pool items in constantPool
, plus 1. The first constant pool item has index 1, and long and double items count for two items. /**
* The number of constant pool items in {@link #constantPool}, plus 1. The first constant pool
* item has index 1, and long and double items count for two items.
*/
private int constantPoolCount;
The content of the ClassFile's constant_pool JVMS structure corresponding to this SymbolTable.
The ClassFile's constant_pool_count field is not included.
/**
* The content of the ClassFile's constant_pool JVMS structure corresponding to this SymbolTable.
* The ClassFile's constant_pool_count field is <i>not</i> included.
*/
private ByteVector constantPool;
The number of bootstrap methods in bootstrapMethods
. Corresponds to the BootstrapMethods_attribute's num_bootstrap_methods field value. /**
* The number of bootstrap methods in {@link #bootstrapMethods}. Corresponds to the
* BootstrapMethods_attribute's num_bootstrap_methods field value.
*/
private int bootstrapMethodCount;
The content of the BootstrapMethods attribute 'bootstrap_methods' array corresponding to this
SymbolTable. Note that the first 6 bytes of the BootstrapMethods_attribute, and its
num_bootstrap_methods field, are not included.
/**
* The content of the BootstrapMethods attribute 'bootstrap_methods' array corresponding to this
* SymbolTable. Note that the first 6 bytes of the BootstrapMethods_attribute, and its
* num_bootstrap_methods field, are <i>not</i> included.
*/
private ByteVector bootstrapMethods;
The actual number of elements in typeTable
. These elements are stored from index 0 to typeCount (excluded). The other array entries are empty. /**
* The actual number of elements in {@link #typeTable}. These elements are stored from index 0 to
* typeCount (excluded). The other array entries are empty.
*/
private int typeCount;
An ASM specific type table used to temporarily store internal names that will not necessarily be stored in the constant pool. This type table is used by the control flow and data flow analysis algorithm used to compute stack map frames from scratch. This array stores Symbol.TYPE_TAG
and Symbol.UNINITIALIZED_TYPE_TAG
) Symbol. The type symbol at index i
has its Symbol.index
equal to i
(and vice versa). /**
* An ASM specific type table used to temporarily store internal names that will not necessarily
* be stored in the constant pool. This type table is used by the control flow and data flow
* analysis algorithm used to compute stack map frames from scratch. This array stores {@link
* Symbol#TYPE_TAG} and {@link Symbol#UNINITIALIZED_TYPE_TAG}) Symbol. The type symbol at index
* {@code i} has its {@link Symbol#index} equal to {@code i} (and vice versa).
*/
private Entry[] typeTable;
Constructs a new, empty SymbolTable for the given ClassWriter.
Params: - classWriter – a ClassWriter.
/**
* Constructs a new, empty SymbolTable for the given ClassWriter.
*
* @param classWriter a ClassWriter.
*/
SymbolTable(final ClassWriter classWriter) {
this.classWriter = classWriter;
this.sourceClassReader = null;
this.entries = new Entry[256];
this.constantPoolCount = 1;
this.constantPool = new ByteVector();
}
Constructs a new SymbolTable for the given ClassWriter, initialized with the constant pool and
bootstrap methods of the given ClassReader.
Params: - classWriter – a ClassWriter.
- classReader – the ClassReader whose constant pool and bootstrap methods must be copied to
initialize the SymbolTable.
/**
* Constructs a new SymbolTable for the given ClassWriter, initialized with the constant pool and
* bootstrap methods of the given ClassReader.
*
* @param classWriter a ClassWriter.
* @param classReader the ClassReader whose constant pool and bootstrap methods must be copied to
* initialize the SymbolTable.
*/
SymbolTable(final ClassWriter classWriter, final ClassReader classReader) {
this.classWriter = classWriter;
this.sourceClassReader = classReader;
// Copy the constant pool binary content.
byte[] inputBytes = classReader.b;
int constantPoolOffset = classReader.getItem(1) - 1;
int constantPoolLength = classReader.header - constantPoolOffset;
constantPoolCount = classReader.getItemCount();
constantPool = new ByteVector(constantPoolLength);
constantPool.putByteArray(inputBytes, constantPoolOffset, constantPoolLength);
// Add the constant pool items in the symbol table entries. Reserve enough space in 'entries' to
// avoid too many hash set collisions (entries is not dynamically resized by the addConstant*
// method calls below), and to account for bootstrap method entries.
entries = new Entry[constantPoolCount * 2];
char[] charBuffer = new char[classReader.getMaxStringLength()];
boolean hasBootstrapMethods = false;
int itemIndex = 1;
while (itemIndex < constantPoolCount) {
int itemOffset = classReader.getItem(itemIndex);
int itemTag = inputBytes[itemOffset - 1];
int nameAndTypeItemOffset;
switch (itemTag) {
case Symbol.CONSTANT_FIELDREF_TAG:
case Symbol.CONSTANT_METHODREF_TAG:
case Symbol.CONSTANT_INTERFACE_METHODREF_TAG:
nameAndTypeItemOffset =
classReader.getItem(classReader.readUnsignedShort(itemOffset + 2));
addConstantMemberReference(
itemIndex,
itemTag,
classReader.readClass(itemOffset, charBuffer),
classReader.readUTF8(nameAndTypeItemOffset, charBuffer),
classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer));
break;
case Symbol.CONSTANT_INTEGER_TAG:
case Symbol.CONSTANT_FLOAT_TAG:
addConstantIntegerOrFloat(itemIndex, itemTag, classReader.readInt(itemOffset));
break;
case Symbol.CONSTANT_NAME_AND_TYPE_TAG:
addConstantNameAndType(
itemIndex,
classReader.readUTF8(itemOffset, charBuffer),
classReader.readUTF8(itemOffset + 2, charBuffer));
break;
case Symbol.CONSTANT_LONG_TAG:
case Symbol.CONSTANT_DOUBLE_TAG:
addConstantLongOrDouble(itemIndex, itemTag, classReader.readLong(itemOffset));
break;
case Symbol.CONSTANT_UTF8_TAG:
addConstantUtf8(itemIndex, classReader.readUtf(itemIndex, charBuffer));
break;
case Symbol.CONSTANT_METHOD_HANDLE_TAG:
int memberRefItemOffset =
classReader.getItem(classReader.readUnsignedShort(itemOffset + 1));
nameAndTypeItemOffset =
classReader.getItem(classReader.readUnsignedShort(memberRefItemOffset + 2));
addConstantMethodHandle(
itemIndex,
classReader.readByte(itemOffset),
classReader.readClass(memberRefItemOffset, charBuffer),
classReader.readUTF8(nameAndTypeItemOffset, charBuffer),
classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer));
break;
case Symbol.CONSTANT_DYNAMIC_TAG:
case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG:
hasBootstrapMethods = true;
nameAndTypeItemOffset =
classReader.getItem(classReader.readUnsignedShort(itemOffset + 2));
addConstantDynamicOrInvokeDynamicReference(
itemTag,
itemIndex,
classReader.readUTF8(nameAndTypeItemOffset, charBuffer),
classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer),
classReader.readUnsignedShort(itemOffset));
break;
case Symbol.CONSTANT_STRING_TAG:
case Symbol.CONSTANT_CLASS_TAG:
case Symbol.CONSTANT_METHOD_TYPE_TAG:
case Symbol.CONSTANT_MODULE_TAG:
case Symbol.CONSTANT_PACKAGE_TAG:
addConstantUtf8Reference(
itemIndex, itemTag, classReader.readUTF8(itemOffset, charBuffer));
break;
default:
throw new IllegalArgumentException();
}
itemIndex +=
(itemTag == Symbol.CONSTANT_LONG_TAG || itemTag == Symbol.CONSTANT_DOUBLE_TAG) ? 2 : 1;
}
// Copy the BootstrapMethods, if any.
if (hasBootstrapMethods) {
copyBootstrapMethods(classReader, charBuffer);
}
}
Read the BootstrapMethods 'bootstrap_methods' array binary content and add them as entries of
the SymbolTable.
Params: - classReader – the ClassReader whose bootstrap methods must be copied to initialize the
SymbolTable.
- charBuffer – a buffer used to read strings in the constant pool.
/**
* Read the BootstrapMethods 'bootstrap_methods' array binary content and add them as entries of
* the SymbolTable.
*
* @param classReader the ClassReader whose bootstrap methods must be copied to initialize the
* SymbolTable.
* @param charBuffer a buffer used to read strings in the constant pool.
*/
private void copyBootstrapMethods(final ClassReader classReader, final char[] charBuffer) {
// Find attributOffset of the 'bootstrap_methods' array.
byte[] inputBytes = classReader.b;
int currentAttributeOffset = classReader.getFirstAttributeOffset();
for (int i = classReader.readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
String attributeName = classReader.readUTF8(currentAttributeOffset, charBuffer);
if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
bootstrapMethodCount = classReader.readUnsignedShort(currentAttributeOffset + 6);
break;
}
currentAttributeOffset += 6 + classReader.readInt(currentAttributeOffset + 2);
}
if (bootstrapMethodCount > 0) {
// Compute the offset and the length of the BootstrapMethods 'bootstrap_methods' array.
int bootstrapMethodsOffset = currentAttributeOffset + 8;
int bootstrapMethodsLength = classReader.readInt(currentAttributeOffset + 2) - 2;
bootstrapMethods = new ByteVector(bootstrapMethodsLength);
bootstrapMethods.putByteArray(inputBytes, bootstrapMethodsOffset, bootstrapMethodsLength);
// Add each bootstrap method in the symbol table entries.
int currentOffset = bootstrapMethodsOffset;
for (int i = 0; i < bootstrapMethodCount; i++) {
int offset = currentOffset - bootstrapMethodsOffset;
int bootstrapMethodRef = classReader.readUnsignedShort(currentOffset);
currentOffset += 2;
int numBootstrapArguments = classReader.readUnsignedShort(currentOffset);
currentOffset += 2;
int hashCode = classReader.readConst(bootstrapMethodRef, charBuffer).hashCode();
while (numBootstrapArguments-- > 0) {
int bootstrapArgument = classReader.readUnsignedShort(currentOffset);
currentOffset += 2;
hashCode ^= classReader.readConst(bootstrapArgument, charBuffer).hashCode();
}
add(new Entry(i, Symbol.BOOTSTRAP_METHOD_TAG, offset, hashCode & 0x7FFFFFFF));
}
}
}
Returns the ClassReader from which this SymbolTable was constructed.
Returns: the ClassReader from which this SymbolTable was constructed, or null if it was constructed from scratch.
/**
* Returns the ClassReader from which this SymbolTable was constructed.
*
* @return the ClassReader from which this SymbolTable was constructed, or {@literal null} if it
* was constructed from scratch.
*/
ClassReader getSource() {
return sourceClassReader;
}
Returns the major version of the class to which this symbol table belongs.
Returns: the major version of the class to which this symbol table belongs.
/**
* Returns the major version of the class to which this symbol table belongs.
*
* @return the major version of the class to which this symbol table belongs.
*/
int getMajorVersion() {
return majorVersion;
}
Returns the internal name of the class to which this symbol table belongs.
Returns: the internal name of the class to which this symbol table belongs.
/**
* Returns the internal name of the class to which this symbol table belongs.
*
* @return the internal name of the class to which this symbol table belongs.
*/
String getClassName() {
return className;
}
Sets the major version and the name of the class to which this symbol table belongs. Also adds
the class name to the constant pool.
Params: - majorVersion – a major ClassFile version number.
- className – an internal class name.
Returns: the constant pool index of a new or already existing Symbol with the given class name.
/**
* Sets the major version and the name of the class to which this symbol table belongs. Also adds
* the class name to the constant pool.
*
* @param majorVersion a major ClassFile version number.
* @param className an internal class name.
* @return the constant pool index of a new or already existing Symbol with the given class name.
*/
int setMajorVersionAndClassName(final int majorVersion, final String className) {
this.majorVersion = majorVersion;
this.className = className;
return addConstantClass(className).index;
}
Returns the number of items in this symbol table's constant_pool array (plus 1).
Returns: the number of items in this symbol table's constant_pool array (plus 1).
/**
* Returns the number of items in this symbol table's constant_pool array (plus 1).
*
* @return the number of items in this symbol table's constant_pool array (plus 1).
*/
int getConstantPoolCount() {
return constantPoolCount;
}
Returns the length in bytes of this symbol table's constant_pool array.
Returns: the length in bytes of this symbol table's constant_pool array.
/**
* Returns the length in bytes of this symbol table's constant_pool array.
*
* @return the length in bytes of this symbol table's constant_pool array.
*/
int getConstantPoolLength() {
return constantPool.length;
}
Puts this symbol table's constant_pool array in the given ByteVector, preceded by the
constant_pool_count value.
Params: - output – where the JVMS ClassFile's constant_pool array must be put.
/**
* Puts this symbol table's constant_pool array in the given ByteVector, preceded by the
* constant_pool_count value.
*
* @param output where the JVMS ClassFile's constant_pool array must be put.
*/
void putConstantPool(final ByteVector output) {
output.putShort(constantPoolCount).putByteArray(constantPool.data, 0, constantPool.length);
}
Returns the size in bytes of this symbol table's BootstrapMethods attribute. Also adds the
attribute name in the constant pool.
Returns: the size in bytes of this symbol table's BootstrapMethods attribute.
/**
* Returns the size in bytes of this symbol table's BootstrapMethods attribute. Also adds the
* attribute name in the constant pool.
*
* @return the size in bytes of this symbol table's BootstrapMethods attribute.
*/
int computeBootstrapMethodsSize() {
if (bootstrapMethods != null) {
addConstantUtf8(Constants.BOOTSTRAP_METHODS);
return 8 + bootstrapMethods.length;
} else {
return 0;
}
}
Puts this symbol table's BootstrapMethods attribute in the given ByteVector. This includes the
6 attribute header bytes and the num_bootstrap_methods value.
Params: - output – where the JVMS BootstrapMethods attribute must be put.
/**
* Puts this symbol table's BootstrapMethods attribute in the given ByteVector. This includes the
* 6 attribute header bytes and the num_bootstrap_methods value.
*
* @param output where the JVMS BootstrapMethods attribute must be put.
*/
void putBootstrapMethods(final ByteVector output) {
if (bootstrapMethods != null) {
output
.putShort(addConstantUtf8(Constants.BOOTSTRAP_METHODS))
.putInt(bootstrapMethods.length + 2)
.putShort(bootstrapMethodCount)
.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length);
}
}
// -----------------------------------------------------------------------------------------------
// Generic symbol table entries management.
// -----------------------------------------------------------------------------------------------
Returns the list of entries which can potentially have the given hash code.
Params: - hashCode – a
Entry.hashCode
value.
Returns: the list of entries which can potentially have the given hash code. The list is stored via the Entry.next
field.
/**
* Returns the list of entries which can potentially have the given hash code.
*
* @param hashCode a {@link Entry#hashCode} value.
* @return the list of entries which can potentially have the given hash code. The list is stored
* via the {@link Entry#next} field.
*/
private Entry get(final int hashCode) {
return entries[hashCode % entries.length];
}
Puts the given entry in the entries
hash set. This method does not check whether entries
already contains a similar entry or not. entries
is resized if necessary to avoid hash collisions (multiple entries needing to be stored at the same entries
array index) as much as possible, with reasonable memory usage. Params: - entry – an Entry (which must not already be contained in
entries
).
Returns: the given entry
/**
* Puts the given entry in the {@link #entries} hash set. This method does <i>not</i> check
* whether {@link #entries} already contains a similar entry or not. {@link #entries} is resized
* if necessary to avoid hash collisions (multiple entries needing to be stored at the same {@link
* #entries} array index) as much as possible, with reasonable memory usage.
*
* @param entry an Entry (which must not already be contained in {@link #entries}).
* @return the given entry
*/
private Entry put(final Entry entry) {
if (entryCount > (entries.length * 3) / 4) {
int currentCapacity = entries.length;
int newCapacity = currentCapacity * 2 + 1;
Entry[] newEntries = new Entry[newCapacity];
for (int i = currentCapacity - 1; i >= 0; --i) {
Entry currentEntry = entries[i];
while (currentEntry != null) {
int newCurrentEntryIndex = currentEntry.hashCode % newCapacity;
Entry nextEntry = currentEntry.next;
currentEntry.next = newEntries[newCurrentEntryIndex];
newEntries[newCurrentEntryIndex] = currentEntry;
currentEntry = nextEntry;
}
}
entries = newEntries;
}
entryCount++;
int index = entry.hashCode % entries.length;
entry.next = entries[index];
return entries[index] = entry;
}
Adds the given entry in the entries
hash set. This method does not check whether entries
already contains a similar entry or not, and does not resize entries
if necessary. Params: - entry – an Entry (which must not already be contained in
entries
).
/**
* Adds the given entry in the {@link #entries} hash set. This method does <i>not</i> check
* whether {@link #entries} already contains a similar entry or not, and does <i>not</i> resize
* {@link #entries} if necessary.
*
* @param entry an Entry (which must not already be contained in {@link #entries}).
*/
private void add(final Entry entry) {
entryCount++;
int index = entry.hashCode % entries.length;
entry.next = entries[index];
entries[index] = entry;
}
// -----------------------------------------------------------------------------------------------
// Constant pool entries management.
// -----------------------------------------------------------------------------------------------
Adds a number or string constant to the constant pool of this symbol table. Does nothing if the
constant pool already contains a similar item.
Params: Returns: a new or already existing Symbol with the given value.
/**
* Adds a number or string constant to the constant pool of this symbol table. Does nothing if the
* constant pool already contains a similar item.
*
* @param value the value of the constant to be added to the constant pool. This parameter must be
* an {@link Integer}, {@link Byte}, {@link Character}, {@link Short}, {@link Boolean}, {@link
* Float}, {@link Long}, {@link Double}, {@link String}, {@link Type} or {@link Handle}.
* @return a new or already existing Symbol with the given value.
*/
Symbol addConstant(final Object value) {
if (value instanceof Integer) {
return addConstantInteger(((Integer) value).intValue());
} else if (value instanceof Byte) {
return addConstantInteger(((Byte) value).intValue());
} else if (value instanceof Character) {
return addConstantInteger(((Character) value).charValue());
} else if (value instanceof Short) {
return addConstantInteger(((Short) value).intValue());
} else if (value instanceof Boolean) {
return addConstantInteger(((Boolean) value).booleanValue() ? 1 : 0);
} else if (value instanceof Float) {
return addConstantFloat(((Float) value).floatValue());
} else if (value instanceof Long) {
return addConstantLong(((Long) value).longValue());
} else if (value instanceof Double) {
return addConstantDouble(((Double) value).doubleValue());
} else if (value instanceof String) {
return addConstantString((String) value);
} else if (value instanceof Type) {
Type type = (Type) value;
int typeSort = type.getSort();
if (typeSort == Type.OBJECT) {
return addConstantClass(type.getInternalName());
} else if (typeSort == Type.METHOD) {
return addConstantMethodType(type.getDescriptor());
} else { // type is a primitive or array type.
return addConstantClass(type.getDescriptor());
}
} else if (value instanceof Handle) {
Handle handle = (Handle) value;
return addConstantMethodHandle(
handle.getTag(),
handle.getOwner(),
handle.getName(),
handle.getDesc(),
handle.isInterface());
} else if (value instanceof ConstantDynamic) {
ConstantDynamic constantDynamic = (ConstantDynamic) value;
return addConstantDynamic(
constantDynamic.getName(),
constantDynamic.getDescriptor(),
constantDynamic.getBootstrapMethod(),
constantDynamic.getBootstrapMethodArgumentsUnsafe());
} else {
throw new IllegalArgumentException("value " + value);
}
}
Adds a CONSTANT_Class_info to the constant pool of this symbol table. Does nothing if the
constant pool already contains a similar item.
Params: - value – the internal name of a class.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_Class_info to the constant pool of this symbol table. Does nothing if the
* constant pool already contains a similar item.
*
* @param value the internal name of a class.
* @return a new or already existing Symbol with the given value.
*/
Symbol addConstantClass(final String value) {
return addConstantUtf8Reference(Symbol.CONSTANT_CLASS_TAG, value);
}
Adds a CONSTANT_Fieldref_info to the constant pool of this symbol table. Does nothing if the
constant pool already contains a similar item.
Params: - owner – the internal name of a class.
- name – a field name.
- descriptor – a field descriptor.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_Fieldref_info to the constant pool of this symbol table. Does nothing if the
* constant pool already contains a similar item.
*
* @param owner the internal name of a class.
* @param name a field name.
* @param descriptor a field descriptor.
* @return a new or already existing Symbol with the given value.
*/
Symbol addConstantFieldref(final String owner, final String name, final String descriptor) {
return addConstantMemberReference(Symbol.CONSTANT_FIELDREF_TAG, owner, name, descriptor);
}
Adds a CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info to the constant pool of this
symbol table. Does nothing if the constant pool already contains a similar item.
Params: - owner – the internal name of a class.
- name – a method name.
- descriptor – a method descriptor.
- isInterface – whether owner is an interface or not.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info to the constant pool of this
* symbol table. Does nothing if the constant pool already contains a similar item.
*
* @param owner the internal name of a class.
* @param name a method name.
* @param descriptor a method descriptor.
* @param isInterface whether owner is an interface or not.
* @return a new or already existing Symbol with the given value.
*/
Symbol addConstantMethodref(
final String owner, final String name, final String descriptor, final boolean isInterface) {
int tag = isInterface ? Symbol.CONSTANT_INTERFACE_METHODREF_TAG : Symbol.CONSTANT_METHODREF_TAG;
return addConstantMemberReference(tag, owner, name, descriptor);
}
Adds a CONSTANT_Fieldref_info, CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info to
the constant pool of this symbol table. Does nothing if the constant pool already contains a
similar item.
Params: - tag – one of
Symbol.CONSTANT_FIELDREF_TAG
, Symbol.CONSTANT_METHODREF_TAG
or Symbol.CONSTANT_INTERFACE_METHODREF_TAG
. - owner – the internal name of a class.
- name – a field or method name.
- descriptor – a field or method descriptor.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_Fieldref_info, CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info to
* the constant pool of this symbol table. Does nothing if the constant pool already contains a
* similar item.
*
* @param tag one of {@link Symbol#CONSTANT_FIELDREF_TAG}, {@link Symbol#CONSTANT_METHODREF_TAG}
* or {@link Symbol#CONSTANT_INTERFACE_METHODREF_TAG}.
* @param owner the internal name of a class.
* @param name a field or method name.
* @param descriptor a field or method descriptor.
* @return a new or already existing Symbol with the given value.
*/
private Entry addConstantMemberReference(
final int tag, final String owner, final String name, final String descriptor) {
int hashCode = hash(tag, owner, name, descriptor);
Entry entry = get(hashCode);
while (entry != null) {
if (entry.tag == tag
&& entry.hashCode == hashCode
&& entry.owner.equals(owner)
&& entry.name.equals(name)
&& entry.value.equals(descriptor)) {
return entry;
}
entry = entry.next;
}
constantPool.put122(
tag, addConstantClass(owner).index, addConstantNameAndType(name, descriptor));
return put(new Entry(constantPoolCount++, tag, owner, name, descriptor, 0, hashCode));
}
Adds a new CONSTANT_Fieldref_info, CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info
to the constant pool of this symbol table.
Params: - index – the constant pool index of the new Symbol.
- tag – one of
Symbol.CONSTANT_FIELDREF_TAG
, Symbol.CONSTANT_METHODREF_TAG
or Symbol.CONSTANT_INTERFACE_METHODREF_TAG
. - owner – the internal name of a class.
- name – a field or method name.
- descriptor – a field or method descriptor.
/**
* Adds a new CONSTANT_Fieldref_info, CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info
* to the constant pool of this symbol table.
*
* @param index the constant pool index of the new Symbol.
* @param tag one of {@link Symbol#CONSTANT_FIELDREF_TAG}, {@link Symbol#CONSTANT_METHODREF_TAG}
* or {@link Symbol#CONSTANT_INTERFACE_METHODREF_TAG}.
* @param owner the internal name of a class.
* @param name a field or method name.
* @param descriptor a field or method descriptor.
*/
private void addConstantMemberReference(
final int index,
final int tag,
final String owner,
final String name,
final String descriptor) {
add(new Entry(index, tag, owner, name, descriptor, 0, hash(tag, owner, name, descriptor)));
}
Adds a CONSTANT_String_info to the constant pool of this symbol table. Does nothing if the
constant pool already contains a similar item.
Params: - value – a string.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_String_info to the constant pool of this symbol table. Does nothing if the
* constant pool already contains a similar item.
*
* @param value a string.
* @return a new or already existing Symbol with the given value.
*/
Symbol addConstantString(final String value) {
return addConstantUtf8Reference(Symbol.CONSTANT_STRING_TAG, value);
}
Adds a CONSTANT_Integer_info to the constant pool of this symbol table. Does nothing if the
constant pool already contains a similar item.
Params: - value – an int.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_Integer_info to the constant pool of this symbol table. Does nothing if the
* constant pool already contains a similar item.
*
* @param value an int.
* @return a new or already existing Symbol with the given value.
*/
Symbol addConstantInteger(final int value) {
return addConstantIntegerOrFloat(Symbol.CONSTANT_INTEGER_TAG, value);
}
Adds a CONSTANT_Float_info to the constant pool of this symbol table. Does nothing if the
constant pool already contains a similar item.
Params: - value – a float.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_Float_info to the constant pool of this symbol table. Does nothing if the
* constant pool already contains a similar item.
*
* @param value a float.
* @return a new or already existing Symbol with the given value.
*/
Symbol addConstantFloat(final float value) {
return addConstantIntegerOrFloat(Symbol.CONSTANT_FLOAT_TAG, Float.floatToRawIntBits(value));
}
Adds a CONSTANT_Integer_info or CONSTANT_Float_info to the constant pool of this symbol table.
Does nothing if the constant pool already contains a similar item.
Params: - tag – one of
Symbol.CONSTANT_INTEGER_TAG
or Symbol.CONSTANT_FLOAT_TAG
. - value – an int or float.
Returns: a constant pool constant with the given tag and primitive values.
/**
* Adds a CONSTANT_Integer_info or CONSTANT_Float_info to the constant pool of this symbol table.
* Does nothing if the constant pool already contains a similar item.
*
* @param tag one of {@link Symbol#CONSTANT_INTEGER_TAG} or {@link Symbol#CONSTANT_FLOAT_TAG}.
* @param value an int or float.
* @return a constant pool constant with the given tag and primitive values.
*/
private Symbol addConstantIntegerOrFloat(final int tag, final int value) {
int hashCode = hash(tag, value);
Entry entry = get(hashCode);
while (entry != null) {
if (entry.tag == tag && entry.hashCode == hashCode && entry.data == value) {
return entry;
}
entry = entry.next;
}
constantPool.putByte(tag).putInt(value);
return put(new Entry(constantPoolCount++, tag, value, hashCode));
}
Adds a new CONSTANT_Integer_info or CONSTANT_Float_info to the constant pool of this symbol
table.
Params: - index – the constant pool index of the new Symbol.
- tag – one of
Symbol.CONSTANT_INTEGER_TAG
or Symbol.CONSTANT_FLOAT_TAG
. - value – an int or float.
/**
* Adds a new CONSTANT_Integer_info or CONSTANT_Float_info to the constant pool of this symbol
* table.
*
* @param index the constant pool index of the new Symbol.
* @param tag one of {@link Symbol#CONSTANT_INTEGER_TAG} or {@link Symbol#CONSTANT_FLOAT_TAG}.
* @param value an int or float.
*/
private void addConstantIntegerOrFloat(final int index, final int tag, final int value) {
add(new Entry(index, tag, value, hash(tag, value)));
}
Adds a CONSTANT_Long_info to the constant pool of this symbol table. Does nothing if the
constant pool already contains a similar item.
Params: - value – a long.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_Long_info to the constant pool of this symbol table. Does nothing if the
* constant pool already contains a similar item.
*
* @param value a long.
* @return a new or already existing Symbol with the given value.
*/
Symbol addConstantLong(final long value) {
return addConstantLongOrDouble(Symbol.CONSTANT_LONG_TAG, value);
}
Adds a CONSTANT_Double_info to the constant pool of this symbol table. Does nothing if the
constant pool already contains a similar item.
Params: - value – a double.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_Double_info to the constant pool of this symbol table. Does nothing if the
* constant pool already contains a similar item.
*
* @param value a double.
* @return a new or already existing Symbol with the given value.
*/
Symbol addConstantDouble(final double value) {
return addConstantLongOrDouble(Symbol.CONSTANT_DOUBLE_TAG, Double.doubleToRawLongBits(value));
}
Adds a CONSTANT_Long_info or CONSTANT_Double_info to the constant pool of this symbol table.
Does nothing if the constant pool already contains a similar item.
Params: - tag – one of
Symbol.CONSTANT_LONG_TAG
or Symbol.CONSTANT_DOUBLE_TAG
. - value – a long or double.
Returns: a constant pool constant with the given tag and primitive values.
/**
* Adds a CONSTANT_Long_info or CONSTANT_Double_info to the constant pool of this symbol table.
* Does nothing if the constant pool already contains a similar item.
*
* @param tag one of {@link Symbol#CONSTANT_LONG_TAG} or {@link Symbol#CONSTANT_DOUBLE_TAG}.
* @param value a long or double.
* @return a constant pool constant with the given tag and primitive values.
*/
private Symbol addConstantLongOrDouble(final int tag, final long value) {
int hashCode = hash(tag, value);
Entry entry = get(hashCode);
while (entry != null) {
if (entry.tag == tag && entry.hashCode == hashCode && entry.data == value) {
return entry;
}
entry = entry.next;
}
int index = constantPoolCount;
constantPool.putByte(tag).putLong(value);
constantPoolCount += 2;
return put(new Entry(index, tag, value, hashCode));
}
Adds a new CONSTANT_Long_info or CONSTANT_Double_info to the constant pool of this symbol
table.
Params: - index – the constant pool index of the new Symbol.
- tag – one of
Symbol.CONSTANT_LONG_TAG
or Symbol.CONSTANT_DOUBLE_TAG
. - value – a long or double.
/**
* Adds a new CONSTANT_Long_info or CONSTANT_Double_info to the constant pool of this symbol
* table.
*
* @param index the constant pool index of the new Symbol.
* @param tag one of {@link Symbol#CONSTANT_LONG_TAG} or {@link Symbol#CONSTANT_DOUBLE_TAG}.
* @param value a long or double.
*/
private void addConstantLongOrDouble(final int index, final int tag, final long value) {
add(new Entry(index, tag, value, hash(tag, value)));
}
Adds a CONSTANT_NameAndType_info to the constant pool of this symbol table. Does nothing if the
constant pool already contains a similar item.
Params: - name – a field or method name.
- descriptor – a field or method descriptor.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_NameAndType_info to the constant pool of this symbol table. Does nothing if the
* constant pool already contains a similar item.
*
* @param name a field or method name.
* @param descriptor a field or method descriptor.
* @return a new or already existing Symbol with the given value.
*/
int addConstantNameAndType(final String name, final String descriptor) {
final int tag = Symbol.CONSTANT_NAME_AND_TYPE_TAG;
int hashCode = hash(tag, name, descriptor);
Entry entry = get(hashCode);
while (entry != null) {
if (entry.tag == tag
&& entry.hashCode == hashCode
&& entry.name.equals(name)
&& entry.value.equals(descriptor)) {
return entry.index;
}
entry = entry.next;
}
constantPool.put122(tag, addConstantUtf8(name), addConstantUtf8(descriptor));
return put(new Entry(constantPoolCount++, tag, name, descriptor, hashCode)).index;
}
Adds a new CONSTANT_NameAndType_info to the constant pool of this symbol table.
Params: - index – the constant pool index of the new Symbol.
- name – a field or method name.
- descriptor – a field or method descriptor.
/**
* Adds a new CONSTANT_NameAndType_info to the constant pool of this symbol table.
*
* @param index the constant pool index of the new Symbol.
* @param name a field or method name.
* @param descriptor a field or method descriptor.
*/
private void addConstantNameAndType(final int index, final String name, final String descriptor) {
final int tag = Symbol.CONSTANT_NAME_AND_TYPE_TAG;
add(new Entry(index, tag, name, descriptor, hash(tag, name, descriptor)));
}
Adds a CONSTANT_Utf8_info to the constant pool of this symbol table. Does nothing if the
constant pool already contains a similar item.
Params: - value – a string.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_Utf8_info to the constant pool of this symbol table. Does nothing if the
* constant pool already contains a similar item.
*
* @param value a string.
* @return a new or already existing Symbol with the given value.
*/
int addConstantUtf8(final String value) {
int hashCode = hash(Symbol.CONSTANT_UTF8_TAG, value);
Entry entry = get(hashCode);
while (entry != null) {
if (entry.tag == Symbol.CONSTANT_UTF8_TAG
&& entry.hashCode == hashCode
&& entry.value.equals(value)) {
return entry.index;
}
entry = entry.next;
}
constantPool.putByte(Symbol.CONSTANT_UTF8_TAG).putUTF8(value);
return put(new Entry(constantPoolCount++, Symbol.CONSTANT_UTF8_TAG, value, hashCode)).index;
}
Adds a new CONSTANT_String_info to the constant pool of this symbol table.
Params: - index – the constant pool index of the new Symbol.
- value – a string.
/**
* Adds a new CONSTANT_String_info to the constant pool of this symbol table.
*
* @param index the constant pool index of the new Symbol.
* @param value a string.
*/
private void addConstantUtf8(final int index, final String value) {
add(new Entry(index, Symbol.CONSTANT_UTF8_TAG, value, hash(Symbol.CONSTANT_UTF8_TAG, value)));
}
Adds a CONSTANT_MethodHandle_info to the constant pool of this symbol table. Does nothing if
the constant pool already contains a similar item.
Params: - referenceKind – one of
Opcodes.H_GETFIELD
, Opcodes.H_GETSTATIC
, Opcodes.H_PUTFIELD
, Opcodes.H_PUTSTATIC
, Opcodes.H_INVOKEVIRTUAL
, Opcodes.H_INVOKESTATIC
, Opcodes.H_INVOKESPECIAL
, Opcodes.H_NEWINVOKESPECIAL
or Opcodes.H_INVOKEINTERFACE
. - owner – the internal name of a class of interface.
- name – a field or method name.
- descriptor – a field or method descriptor.
- isInterface – whether owner is an interface or not.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_MethodHandle_info to the constant pool of this symbol table. Does nothing if
* the constant pool already contains a similar item.
*
* @param referenceKind one of {@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 a class of interface.
* @param name a field or method name.
* @param descriptor a field or method descriptor.
* @param isInterface whether owner is an interface or not.
* @return a new or already existing Symbol with the given value.
*/
Symbol addConstantMethodHandle(
final int referenceKind,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG;
// Note that we don't need to include isInterface in the hash computation, because it is
// redundant with owner (we can't have the same owner with different isInterface values).
int hashCode = hash(tag, owner, name, descriptor, referenceKind);
Entry entry = get(hashCode);
while (entry != null) {
if (entry.tag == tag
&& entry.hashCode == hashCode
&& entry.data == referenceKind
&& entry.owner.equals(owner)
&& entry.name.equals(name)
&& entry.value.equals(descriptor)) {
return entry;
}
entry = entry.next;
}
if (referenceKind <= Opcodes.H_PUTSTATIC) {
constantPool.put112(tag, referenceKind, addConstantFieldref(owner, name, descriptor).index);
} else {
constantPool.put112(
tag, referenceKind, addConstantMethodref(owner, name, descriptor, isInterface).index);
}
return put(
new Entry(constantPoolCount++, tag, owner, name, descriptor, referenceKind, hashCode));
}
Adds a new CONSTANT_MethodHandle_info to the constant pool of this symbol table.
Params: - index – the constant pool index of the new Symbol.
- referenceKind – one of
Opcodes.H_GETFIELD
, Opcodes.H_GETSTATIC
, Opcodes.H_PUTFIELD
, Opcodes.H_PUTSTATIC
, Opcodes.H_INVOKEVIRTUAL
, Opcodes.H_INVOKESTATIC
, Opcodes.H_INVOKESPECIAL
, Opcodes.H_NEWINVOKESPECIAL
or Opcodes.H_INVOKEINTERFACE
. - owner – the internal name of a class of interface.
- name – a field or method name.
- descriptor – a field or method descriptor.
/**
* Adds a new CONSTANT_MethodHandle_info to the constant pool of this symbol table.
*
* @param index the constant pool index of the new Symbol.
* @param referenceKind one of {@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 a class of interface.
* @param name a field or method name.
* @param descriptor a field or method descriptor.
*/
private void addConstantMethodHandle(
final int index,
final int referenceKind,
final String owner,
final String name,
final String descriptor) {
final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG;
int hashCode = hash(tag, owner, name, descriptor, referenceKind);
add(new Entry(index, tag, owner, name, descriptor, referenceKind, hashCode));
}
Adds a CONSTANT_MethodType_info to the constant pool of this symbol table. Does nothing if the
constant pool already contains a similar item.
Params: - methodDescriptor – a method descriptor.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_MethodType_info to the constant pool of this symbol table. Does nothing if the
* constant pool already contains a similar item.
*
* @param methodDescriptor a method descriptor.
* @return a new or already existing Symbol with the given value.
*/
Symbol addConstantMethodType(final String methodDescriptor) {
return addConstantUtf8Reference(Symbol.CONSTANT_METHOD_TYPE_TAG, methodDescriptor);
}
Adds a CONSTANT_Dynamic_info to the constant pool of this symbol table. Also adds the related
bootstrap method to the BootstrapMethods of this symbol table. Does nothing if the constant
pool already contains a similar item.
Params: - name – a method name.
- descriptor – a field descriptor.
- bootstrapMethodHandle – a bootstrap method handle.
- bootstrapMethodArguments – the bootstrap method arguments.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_Dynamic_info to the constant pool of this symbol table. Also adds the related
* bootstrap method to the BootstrapMethods of this symbol table. Does nothing if the constant
* pool already contains a similar item.
*
* @param name a method name.
* @param descriptor a field descriptor.
* @param bootstrapMethodHandle a bootstrap method handle.
* @param bootstrapMethodArguments the bootstrap method arguments.
* @return a new or already existing Symbol with the given value.
*/
Symbol addConstantDynamic(
final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) {
Symbol bootstrapMethod = addBootstrapMethod(bootstrapMethodHandle, bootstrapMethodArguments);
return addConstantDynamicOrInvokeDynamicReference(
Symbol.CONSTANT_DYNAMIC_TAG, name, descriptor, bootstrapMethod.index);
}
Adds a CONSTANT_InvokeDynamic_info to the constant pool of this symbol table. Also adds the
related bootstrap method to the BootstrapMethods of this symbol table. Does nothing if the
constant pool already contains a similar item.
Params: - name – a method name.
- descriptor – a method descriptor.
- bootstrapMethodHandle – a bootstrap method handle.
- bootstrapMethodArguments – the bootstrap method arguments.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_InvokeDynamic_info to the constant pool of this symbol table. Also adds the
* related bootstrap method to the BootstrapMethods of this symbol table. Does nothing if the
* constant pool already contains a similar item.
*
* @param name a method name.
* @param descriptor a method descriptor.
* @param bootstrapMethodHandle a bootstrap method handle.
* @param bootstrapMethodArguments the bootstrap method arguments.
* @return a new or already existing Symbol with the given value.
*/
Symbol addConstantInvokeDynamic(
final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) {
Symbol bootstrapMethod = addBootstrapMethod(bootstrapMethodHandle, bootstrapMethodArguments);
return addConstantDynamicOrInvokeDynamicReference(
Symbol.CONSTANT_INVOKE_DYNAMIC_TAG, name, descriptor, bootstrapMethod.index);
}
Adds a CONSTANT_Dynamic or a CONSTANT_InvokeDynamic_info to the constant pool of this symbol
table. Does nothing if the constant pool already contains a similar item.
Params: - tag – one of
Symbol.CONSTANT_DYNAMIC_TAG
or Symbol.CONSTANT_INVOKE_DYNAMIC_TAG
. - name – a method name.
- descriptor – a field descriptor for CONSTANT_DYNAMIC_TAG) or a method descriptor for
CONSTANT_INVOKE_DYNAMIC_TAG.
- bootstrapMethodIndex – the index of a bootstrap method in the BootstrapMethods attribute.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_Dynamic or a CONSTANT_InvokeDynamic_info to the constant pool of this symbol
* table. Does nothing if the constant pool already contains a similar item.
*
* @param tag one of {@link Symbol#CONSTANT_DYNAMIC_TAG} or {@link
* Symbol#CONSTANT_INVOKE_DYNAMIC_TAG}.
* @param name a method name.
* @param descriptor a field descriptor for CONSTANT_DYNAMIC_TAG) or a method descriptor for
* CONSTANT_INVOKE_DYNAMIC_TAG.
* @param bootstrapMethodIndex the index of a bootstrap method in the BootstrapMethods attribute.
* @return a new or already existing Symbol with the given value.
*/
private Symbol addConstantDynamicOrInvokeDynamicReference(
final int tag, final String name, final String descriptor, final int bootstrapMethodIndex) {
int hashCode = hash(tag, name, descriptor, bootstrapMethodIndex);
Entry entry = get(hashCode);
while (entry != null) {
if (entry.tag == tag
&& entry.hashCode == hashCode
&& entry.data == bootstrapMethodIndex
&& entry.name.equals(name)
&& entry.value.equals(descriptor)) {
return entry;
}
entry = entry.next;
}
constantPool.put122(tag, bootstrapMethodIndex, addConstantNameAndType(name, descriptor));
return put(
new Entry(
constantPoolCount++, tag, null, name, descriptor, bootstrapMethodIndex, hashCode));
}
Adds a new CONSTANT_Dynamic_info or CONSTANT_InvokeDynamic_info to the constant pool of this
symbol table.
Params: - tag – one of
Symbol.CONSTANT_DYNAMIC_TAG
or Symbol.CONSTANT_INVOKE_DYNAMIC_TAG
. - index – the constant pool index of the new Symbol.
- name – a method name.
- descriptor – a field descriptor for CONSTANT_DYNAMIC_TAG or a method descriptor for
CONSTANT_INVOKE_DYNAMIC_TAG.
- bootstrapMethodIndex – the index of a bootstrap method in the BootstrapMethods attribute.
/**
* Adds a new CONSTANT_Dynamic_info or CONSTANT_InvokeDynamic_info to the constant pool of this
* symbol table.
*
* @param tag one of {@link Symbol#CONSTANT_DYNAMIC_TAG} or {@link
* Symbol#CONSTANT_INVOKE_DYNAMIC_TAG}.
* @param index the constant pool index of the new Symbol.
* @param name a method name.
* @param descriptor a field descriptor for CONSTANT_DYNAMIC_TAG or a method descriptor for
* CONSTANT_INVOKE_DYNAMIC_TAG.
* @param bootstrapMethodIndex the index of a bootstrap method in the BootstrapMethods attribute.
*/
private void addConstantDynamicOrInvokeDynamicReference(
final int tag,
final int index,
final String name,
final String descriptor,
final int bootstrapMethodIndex) {
int hashCode = hash(tag, name, descriptor, bootstrapMethodIndex);
add(new Entry(index, tag, null, name, descriptor, bootstrapMethodIndex, hashCode));
}
Adds a CONSTANT_Module_info to the constant pool of this symbol table. Does nothing if the
constant pool already contains a similar item.
Params: - moduleName – a fully qualified name (using dots) of a module.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_Module_info to the constant pool of this symbol table. Does nothing if the
* constant pool already contains a similar item.
*
* @param moduleName a fully qualified name (using dots) of a module.
* @return a new or already existing Symbol with the given value.
*/
Symbol addConstantModule(final String moduleName) {
return addConstantUtf8Reference(Symbol.CONSTANT_MODULE_TAG, moduleName);
}
Adds a CONSTANT_Package_info to the constant pool of this symbol table. Does nothing if the
constant pool already contains a similar item.
Params: - packageName – the internal name of a package.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_Package_info to the constant pool of this symbol table. Does nothing if the
* constant pool already contains a similar item.
*
* @param packageName the internal name of a package.
* @return a new or already existing Symbol with the given value.
*/
Symbol addConstantPackage(final String packageName) {
return addConstantUtf8Reference(Symbol.CONSTANT_PACKAGE_TAG, packageName);
}
Adds a CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info,
CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table. Does
nothing if the constant pool already contains a similar item.
Params: - tag – one of
Symbol.CONSTANT_CLASS_TAG
, Symbol.CONSTANT_STRING_TAG
, Symbol.CONSTANT_METHOD_TYPE_TAG
, Symbol.CONSTANT_MODULE_TAG
or Symbol.CONSTANT_PACKAGE_TAG
. - value – an internal class name, an arbitrary string, a method descriptor, a module or a
package name, depending on tag.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info,
* CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table. Does
* nothing if the constant pool already contains a similar item.
*
* @param tag one of {@link Symbol#CONSTANT_CLASS_TAG}, {@link Symbol#CONSTANT_STRING_TAG}, {@link
* Symbol#CONSTANT_METHOD_TYPE_TAG}, {@link Symbol#CONSTANT_MODULE_TAG} or {@link
* Symbol#CONSTANT_PACKAGE_TAG}.
* @param value an internal class name, an arbitrary string, a method descriptor, a module or a
* package name, depending on tag.
* @return a new or already existing Symbol with the given value.
*/
private Symbol addConstantUtf8Reference(final int tag, final String value) {
int hashCode = hash(tag, value);
Entry entry = get(hashCode);
while (entry != null) {
if (entry.tag == tag && entry.hashCode == hashCode && entry.value.equals(value)) {
return entry;
}
entry = entry.next;
}
constantPool.put12(tag, addConstantUtf8(value));
return put(new Entry(constantPoolCount++, tag, value, hashCode));
}
Adds a new CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info,
CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table.
Params: - index – the constant pool index of the new Symbol.
- tag – one of
Symbol.CONSTANT_CLASS_TAG
, Symbol.CONSTANT_STRING_TAG
, Symbol.CONSTANT_METHOD_TYPE_TAG
, Symbol.CONSTANT_MODULE_TAG
or Symbol.CONSTANT_PACKAGE_TAG
. - value – an internal class name, an arbitrary string, a method descriptor, a module or a
package name, depending on tag.
/**
* Adds a new CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info,
* CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table.
*
* @param index the constant pool index of the new Symbol.
* @param tag one of {@link Symbol#CONSTANT_CLASS_TAG}, {@link Symbol#CONSTANT_STRING_TAG}, {@link
* Symbol#CONSTANT_METHOD_TYPE_TAG}, {@link Symbol#CONSTANT_MODULE_TAG} or {@link
* Symbol#CONSTANT_PACKAGE_TAG}.
* @param value an internal class name, an arbitrary string, a method descriptor, a module or a
* package name, depending on tag.
*/
private void addConstantUtf8Reference(final int index, final int tag, final String value) {
add(new Entry(index, tag, value, hash(tag, value)));
}
// -----------------------------------------------------------------------------------------------
// Bootstrap method entries management.
// -----------------------------------------------------------------------------------------------
Adds a bootstrap method to the BootstrapMethods attribute of this symbol table. Does nothing if
the BootstrapMethods already contains a similar bootstrap method.
Params: - bootstrapMethodHandle – a bootstrap method handle.
- bootstrapMethodArguments – the bootstrap method arguments.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a bootstrap method to the BootstrapMethods attribute of this symbol table. Does nothing if
* the BootstrapMethods already contains a similar bootstrap method.
*
* @param bootstrapMethodHandle a bootstrap method handle.
* @param bootstrapMethodArguments the bootstrap method arguments.
* @return a new or already existing Symbol with the given value.
*/
Symbol addBootstrapMethod(
final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments) {
ByteVector bootstrapMethodsAttribute = bootstrapMethods;
if (bootstrapMethodsAttribute == null) {
bootstrapMethodsAttribute = bootstrapMethods = new ByteVector();
}
// The bootstrap method arguments can be Constant_Dynamic values, which reference other
// bootstrap methods. We must therefore add the bootstrap method arguments to the constant pool
// and BootstrapMethods attribute first, so that the BootstrapMethods attribute is not modified
// while adding the given bootstrap method to it, in the rest of this method.
for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
addConstant(bootstrapMethodArgument);
}
// Write the bootstrap method in the BootstrapMethods table. This is necessary to be able to
// compare it with existing ones, and will be reverted below if there is already a similar
// bootstrap method.
int bootstrapMethodOffset = bootstrapMethodsAttribute.length;
bootstrapMethodsAttribute.putShort(
addConstantMethodHandle(
bootstrapMethodHandle.getTag(),
bootstrapMethodHandle.getOwner(),
bootstrapMethodHandle.getName(),
bootstrapMethodHandle.getDesc(),
bootstrapMethodHandle.isInterface())
.index);
int numBootstrapArguments = bootstrapMethodArguments.length;
bootstrapMethodsAttribute.putShort(numBootstrapArguments);
for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
bootstrapMethodsAttribute.putShort(addConstant(bootstrapMethodArgument).index);
}
// Compute the length and the hash code of the bootstrap method.
int bootstrapMethodlength = bootstrapMethodsAttribute.length - bootstrapMethodOffset;
int hashCode = bootstrapMethodHandle.hashCode();
for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
hashCode ^= bootstrapMethodArgument.hashCode();
}
hashCode &= 0x7FFFFFFF;
// Add the bootstrap method to the symbol table or revert the above changes.
return addBootstrapMethod(bootstrapMethodOffset, bootstrapMethodlength, hashCode);
}
Adds a bootstrap method to the BootstrapMethods attribute of this symbol table. Does nothing if the BootstrapMethods already contains a similar bootstrap method (more precisely, reverts the content of bootstrapMethods
to remove the last, duplicate bootstrap method). Params: - offset – the offset of the last bootstrap method in
bootstrapMethods
, in bytes. - length – the length of this bootstrap method in
bootstrapMethods
, in bytes. - hashCode – the hash code of this bootstrap method.
Returns: a new or already existing Symbol with the given value.
/**
* Adds a bootstrap method to the BootstrapMethods attribute of this symbol table. Does nothing if
* the BootstrapMethods already contains a similar bootstrap method (more precisely, reverts the
* content of {@link #bootstrapMethods} to remove the last, duplicate bootstrap method).
*
* @param offset the offset of the last bootstrap method in {@link #bootstrapMethods}, in bytes.
* @param length the length of this bootstrap method in {@link #bootstrapMethods}, in bytes.
* @param hashCode the hash code of this bootstrap method.
* @return a new or already existing Symbol with the given value.
*/
private Symbol addBootstrapMethod(final int offset, final int length, final int hashCode) {
final byte[] bootstrapMethodsData = bootstrapMethods.data;
Entry entry = get(hashCode);
while (entry != null) {
if (entry.tag == Symbol.BOOTSTRAP_METHOD_TAG && entry.hashCode == hashCode) {
int otherOffset = (int) entry.data;
boolean isSameBootstrapMethod = true;
for (int i = 0; i < length; ++i) {
if (bootstrapMethodsData[offset + i] != bootstrapMethodsData[otherOffset + i]) {
isSameBootstrapMethod = false;
break;
}
}
if (isSameBootstrapMethod) {
bootstrapMethods.length = offset; // Revert to old position.
return entry;
}
}
entry = entry.next;
}
return put(new Entry(bootstrapMethodCount++, Symbol.BOOTSTRAP_METHOD_TAG, offset, hashCode));
}
// -----------------------------------------------------------------------------------------------
// Type table entries management.
// -----------------------------------------------------------------------------------------------
Returns the type table element whose index is given.
Params: - typeIndex – a type table index.
Returns: the type table element whose index is given.
/**
* Returns the type table element whose index is given.
*
* @param typeIndex a type table index.
* @return the type table element whose index is given.
*/
Symbol getType(final int typeIndex) {
return typeTable[typeIndex];
}
Adds a type in the type table of this symbol table. Does nothing if the type table already
contains a similar type.
Params: - value – an internal class name.
Returns: the index of a new or already existing type Symbol with the given value.
/**
* Adds a type in the type table of this symbol table. Does nothing if the type table already
* contains a similar type.
*
* @param value an internal class name.
* @return the index of a new or already existing type Symbol with the given value.
*/
int addType(final String value) {
int hashCode = hash(Symbol.TYPE_TAG, value);
Entry entry = get(hashCode);
while (entry != null) {
if (entry.tag == Symbol.TYPE_TAG && entry.hashCode == hashCode && entry.value.equals(value)) {
return entry.index;
}
entry = entry.next;
}
return addTypeInternal(new Entry(typeCount, Symbol.TYPE_TAG, value, hashCode));
}
Adds an Frame.ITEM_UNINITIALIZED
type in the type table of this symbol table. Does nothing if the type table already contains a similar type. Params: - value – an internal class name.
- bytecodeOffset – the bytecode offset of the NEW instruction that created this
Frame.ITEM_UNINITIALIZED
type value.
Returns: the index of a new or already existing type Symbol with the given value.
/**
* Adds an {@link Frame#ITEM_UNINITIALIZED} type in the type table of this symbol table. Does
* nothing if the type table already contains a similar type.
*
* @param value an internal class name.
* @param bytecodeOffset the bytecode offset of the NEW instruction that created this {@link
* Frame#ITEM_UNINITIALIZED} type value.
* @return the index of a new or already existing type Symbol with the given value.
*/
int addUninitializedType(final String value, final int bytecodeOffset) {
int hashCode = hash(Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset);
Entry entry = get(hashCode);
while (entry != null) {
if (entry.tag == Symbol.UNINITIALIZED_TYPE_TAG
&& entry.hashCode == hashCode
&& entry.data == bytecodeOffset
&& entry.value.equals(value)) {
return entry.index;
}
entry = entry.next;
}
return addTypeInternal(
new Entry(typeCount, Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset, hashCode));
}
Adds a merged type in the type table of this symbol table. Does nothing if the type table
already contains a similar type.
Params: - typeTableIndex1 – a
Symbol.TYPE_TAG
type, specified by its index in the type table. - typeTableIndex2 – another
Symbol.TYPE_TAG
type, specified by its index in the type table.
Returns: the index of a new or already existing Symbol.TYPE_TAG
type Symbol, corresponding to the common super class of the given types.
/**
* Adds a merged type in the type table of this symbol table. Does nothing if the type table
* already contains a similar type.
*
* @param typeTableIndex1 a {@link Symbol#TYPE_TAG} type, specified by its index in the type
* table.
* @param typeTableIndex2 another {@link Symbol#TYPE_TAG} type, specified by its index in the type
* table.
* @return the index of a new or already existing {@link Symbol#TYPE_TAG} type Symbol,
* corresponding to the common super class of the given types.
*/
int addMergedType(final int typeTableIndex1, final int typeTableIndex2) {
// TODO sort the arguments? The merge result should be independent of their order.
long data = typeTableIndex1 | (((long) typeTableIndex2) << 32);
int hashCode = hash(Symbol.MERGED_TYPE_TAG, typeTableIndex1 + typeTableIndex2);
Entry entry = get(hashCode);
while (entry != null) {
if (entry.tag == Symbol.MERGED_TYPE_TAG && entry.hashCode == hashCode && entry.data == data) {
return entry.info;
}
entry = entry.next;
}
String type1 = typeTable[typeTableIndex1].value;
String type2 = typeTable[typeTableIndex2].value;
int commonSuperTypeIndex = addType(classWriter.getCommonSuperClass(type1, type2));
put(new Entry(typeCount, Symbol.MERGED_TYPE_TAG, data, hashCode)).info = commonSuperTypeIndex;
return commonSuperTypeIndex;
}
Adds the given type Symbol to typeTable
. Params: - entry – a
Symbol.TYPE_TAG
or Symbol.UNINITIALIZED_TYPE_TAG
type symbol. The index of this Symbol must be equal to the current value of typeCount
.
Returns: the index in typeTable
where the given type was added, which is also equal to entry's index by hypothesis.
/**
* Adds the given type Symbol to {@link #typeTable}.
*
* @param entry a {@link Symbol#TYPE_TAG} or {@link Symbol#UNINITIALIZED_TYPE_TAG} type symbol.
* The index of this Symbol must be equal to the current value of {@link #typeCount}.
* @return the index in {@link #typeTable} where the given type was added, which is also equal to
* entry's index by hypothesis.
*/
private int addTypeInternal(final Entry entry) {
if (typeTable == null) {
typeTable = new Entry[16];
}
if (typeCount == typeTable.length) {
Entry[] newTypeTable = new Entry[2 * typeTable.length];
System.arraycopy(typeTable, 0, newTypeTable, 0, typeTable.length);
typeTable = newTypeTable;
}
typeTable[typeCount++] = entry;
return put(entry).index;
}
// -----------------------------------------------------------------------------------------------
// Static helper methods to compute hash codes.
// -----------------------------------------------------------------------------------------------
private static int hash(final int tag, final int value) {
return 0x7FFFFFFF & (tag + value);
}
private static int hash(final int tag, final long value) {
return 0x7FFFFFFF & (tag + (int) value + (int) (value >>> 32));
}
private static int hash(final int tag, final String value) {
return 0x7FFFFFFF & (tag + value.hashCode());
}
private static int hash(final int tag, final String value1, final int value2) {
return 0x7FFFFFFF & (tag + value1.hashCode() + value2);
}
private static int hash(final int tag, final String value1, final String value2) {
return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode());
}
private static int hash(
final int tag, final String value1, final String value2, final int value3) {
return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * (value3 + 1));
}
private static int hash(
final int tag, final String value1, final String value2, final String value3) {
return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * value3.hashCode());
}
private static int hash(
final int tag,
final String value1,
final String value2,
final String value3,
final int value4) {
return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * value3.hashCode() * value4);
}
An entry of a SymbolTable. This concrete and private subclass of Symbol
adds two fields which are only used inside SymbolTable, to implement hash sets of symbols (in order to avoid duplicate symbols). See SymbolTable.entries
. Author: Eric Bruneton
/**
* An entry of a SymbolTable. This concrete and private subclass of {@link Symbol} adds two fields
* which are only used inside SymbolTable, to implement hash sets of symbols (in order to avoid
* duplicate symbols). See {@link #entries}.
*
* @author Eric Bruneton
*/
private static class Entry extends Symbol {
The hash code of this entry. /** The hash code of this entry. */
final int hashCode;
Another entry (and so on recursively) having the same hash code (modulo the size of SymbolTable.entries
) as this one. /**
* Another entry (and so on recursively) having the same hash code (modulo the size of {@link
* #entries}) as this one.
*/
Entry next;
Entry(
final int index,
final int tag,
final String owner,
final String name,
final String value,
final long data,
final int hashCode) {
super(index, tag, owner, name, value, data);
this.hashCode = hashCode;
}
Entry(final int index, final int tag, final String value, final int hashCode) {
super(index, tag, /* owner = */ null, /* name = */ null, value, /* data = */ 0);
this.hashCode = hashCode;
}
Entry(final int index, final int tag, final String value, final long data, final int hashCode) {
super(index, tag, /* owner = */ null, /* name = */ null, value, data);
this.hashCode = hashCode;
}
Entry(
final int index, final int tag, final String name, final String value, final int hashCode) {
super(index, tag, /* owner = */ null, name, value, /* data = */ 0);
this.hashCode = hashCode;
}
Entry(final int index, final int tag, final long data, final int hashCode) {
super(index, tag, /* owner = */ null, /* name = */ null, /* value = */ null, data);
this.hashCode = hashCode;
}
}
}