shade.com.alibaba.fastjson2.internal.asm.SymbolTable Maven / Gradle / Ivy
// 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 com.alibaba.fastjson2.internal.asm;
/**
* The constant pool entries, the BootstrapMethods attribute entries and the (ASM specific) type
* table entries of a class.
*
* @author Eric Bruneton
* @see JVMS
* 4.4
* @see JVMS
* 4.7.23
*/
final class SymbolTable {
final ClassWriter classWriter;
/**
* The internal name of the class to which this symbol table belongs.
*/
String className;
private int entryCount;
private Symbol[] entries;
/**
* 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.
*/
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.
*/
final ByteVector constantPool;
/**
* 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;
Symbol[] typeTable;
/**
* Constructs a new, empty SymbolTable for the given ClassWriter.
*
* @param classWriter a ClassWriter.
*/
SymbolTable(final ClassWriter classWriter) {
this.classWriter = classWriter;
this.entries = new Symbol[256];
this.constantPoolCount = 1;
this.constantPool = new ByteVector(4096);
}
//
// /**
// * 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.
*
* @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) {
/**
* The major version number of the class to which this symbol table belongs.
*/
this.className = className;
return addConstantUtf8Reference(/*CONSTANT_CLASS_TAG*/ 7, className).index;
}
//
// /**
// * 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.
// *
// * @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.
// *
// * @return the size in bytes of this symbol table's BootstrapMethods attribute.
// */
// int computeBootstrapMethodsSize() {
// 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.
// *
// * @param output where the JVMS BootstrapMethods attribute must be put.
// */
// void putBootstrapMethods(final ByteVector output) {
// }
// -----------------------------------------------------------------------------------------------
// Generic symbol table entries management.
// -----------------------------------------------------------------------------------------------
//
// /**
// * 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 {@link #entries} hash set. This method does not 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 Symbol put(final Symbol entry) {
if (entryCount > (entries.length * 3) / 4) {
int currentCapacity = entries.length;
int newCapacity = currentCapacity * 2 + 1;
Symbol[] newEntries = new Symbol[newCapacity];
for (int i = currentCapacity - 1; i >= 0; --i) {
Symbol currentEntry = entries[i];
while (currentEntry != null) {
int newCurrentEntryIndex = currentEntry.hashCode % newCapacity;
Symbol 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;
}
// -----------------------------------------------------------------------------------------------
// 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.
// *
// * @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}.
// * @return a new or already existing Symbol with the given value.
// */
// Symbol addConstant(final Object value) {
// if (value instanceof Integer) {
// return addConstantIntegerOrFloat(Symbol.CONSTANT_INTEGER_TAG, ((Integer) value).intValue());
// } else if (value instanceof Byte) {
// return addConstantIntegerOrFloat(Symbol.CONSTANT_INTEGER_TAG, ((Byte) value).intValue());
// } else if (value instanceof Character) {
// return addConstantIntegerOrFloat(Symbol.CONSTANT_INTEGER_TAG, ((Character) value).charValue());
// } else if (value instanceof Short) {
// return addConstantIntegerOrFloat(Symbol.CONSTANT_INTEGER_TAG, ((Short) value).intValue());
// } else if (value instanceof Boolean) {
// return addConstantIntegerOrFloat(Symbol.CONSTANT_INTEGER_TAG, ((Boolean) value).booleanValue() ? 1 : 0);
// } else if (value instanceof Float) {
// float floatValue = ((Float) value).floatValue();
// return addConstantIntegerOrFloat(Symbol.CONSTANT_FLOAT_TAG, Float.floatToRawIntBits(floatValue));
// } else if (value instanceof Long) {
// return addConstantLongOrDouble(Symbol.CONSTANT_LONG_TAG, ((Long) value).longValue());
// } else if (value instanceof Double) {
// double doubleValue = ((Double) value).doubleValue();
// return addConstantLongOrDouble(Symbol.CONSTANT_DOUBLE_TAG, Double.doubleToRawLongBits(doubleValue));
// } else if (value instanceof String) {
// return addConstantUtf8Reference(Symbol.CONSTANT_STRING_TAG, (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 addConstantUtf8Reference(Symbol.CONSTANT_METHOD_TYPE_TAG, type.getDescriptor());
// } else { // type is a primitive or array type.
// return addConstantClass(type.getDescriptor());
// }
// } 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.
// *
// * @param value the internal name of a class.
// * @return a new or already existing Symbol with the given value.
// */
// Symbol addConstantClass(final String value) {
// final int CONSTANT_CLASS_TAG = 7;
// return addConstantUtf8Reference(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.
// *
// * @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(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.
// *
// * @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) {
// final int CONSTANT_METHODREF_TAG = 10;
// final int CONSTANT_INTERFACE_METHODREF_TAG = 11;
// int tag = isInterface ? /*CONSTANT_INTERFACE_METHODREF_TAG*/ 11 : /*CONSTANT_METHODREF_TAG*/ 10;
// return addConstantMemberReference(
// isInterface ? /*CONSTANT_INTERFACE_METHODREF_TAG*/ 11 : /*CONSTANT_METHODREF_TAG*/ 10
// , owner, name, descriptor
// );
// }
Symbol addConstantMemberReference(
final int tag, final String owner, final String name, final String descriptor) {
// int hashCode = hash(tag, owner, name, descriptor);
int hashCode = 0x7FFFFFFF & (tag + owner.hashCode() * name.hashCode() * descriptor.hashCode());
Symbol entry = entries[hashCode % entries.length];
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, addConstantUtf8Reference(/*CONSTANT_CLASS_TAG*/ 7, owner).index, addConstantNameAndType(name, descriptor));
return put(new Symbol(constantPoolCount++, tag, owner, name, descriptor, 0, hashCode));
}
Symbol addConstantIntegerOrFloat(final int value) {
int hashCode = 0x7FFFFFFF & (3 + value);
Symbol entry = entries[hashCode % entries.length];
while (entry != null) {
if (entry.tag == 3 && entry.hashCode == hashCode && entry.data == value) {
return entry;
}
entry = entry.next;
}
constantPool.putByte(3).putInt(value);
return put(new Symbol(constantPoolCount++, 3, null, null, null, value, hashCode));
}
Symbol addConstantLongOrDouble(final long value) {
int hashCode = 0x7FFFFFFF & (5 + (int) value + (int) (value >>> 32));
Symbol entry = entries[hashCode % entries.length];
while (entry != null) {
if (entry.tag == 5 && entry.hashCode == hashCode && entry.data == value) {
return entry;
}
entry = entry.next;
}
int index = constantPoolCount;
constantPool.putByte(5).putLong(value);
constantPoolCount += 2;
return put(new Symbol(index, 5, null, null, null, value, hashCode));
}
/**
* 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 = 12; // CONSTANT_NAME_AND_TYPE_TAG
int hashCode = 0x7FFFFFFF & (tag + name.hashCode() * descriptor.hashCode());
Symbol entry = entries[hashCode % entries.length];
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 Symbol(constantPoolCount++, tag, null, name, descriptor, 0, hashCode)).index;
}
/**
* 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) {
final int CONSTANT_UTF8_TAG = 1;
int hashCode = 0x7FFFFFFF & (CONSTANT_UTF8_TAG + value.hashCode());
Symbol entry = entries[hashCode % entries.length];
while (entry != null) {
if (entry.tag == CONSTANT_UTF8_TAG
&& entry.hashCode == hashCode
&& entry.value.equals(value)) {
return entry.index;
}
entry = entry.next;
}
constantPool.putByte(CONSTANT_UTF8_TAG).putUTF8(value);
return put(new Symbol(constantPoolCount++, CONSTANT_UTF8_TAG, null, null, value, 0, hashCode)).index;
}
Symbol addConstantUtf8Reference(final int tag, final String value) {
int hashCode = 0x7FFFFFFF & (tag + value.hashCode());
Symbol entry = entries[hashCode % entries.length];
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 Symbol(constantPoolCount++, tag, null, null, value, 0, hashCode));
}
//
// /**
// * 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.
*
* @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) {
final int TYPE_TAG = 128;
int hashCode = 0x7FFFFFFF & (TYPE_TAG + value.hashCode());
Symbol entry = entries[hashCode % entries.length];
while (entry != null) {
if (entry.tag == TYPE_TAG && entry.hashCode == hashCode && entry.value.equals(value)) {
return entry.index;
}
entry = entry.next;
}
return addTypeInternal(new Symbol(typeCount, TYPE_TAG, null, null, value, 0, hashCode));
}
/**
* 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) {
final int UNINITIALIZED_TYPE_TAG = 129;
int hashCode = 0x7FFFFFFF & (UNINITIALIZED_TYPE_TAG + value.hashCode() + bytecodeOffset);
Symbol entry = entries[hashCode % entries.length];
while (entry != null) {
if (entry.tag == UNINITIALIZED_TYPE_TAG
&& entry.hashCode == hashCode
&& entry.data == bytecodeOffset
&& entry.value.equals(value)) {
return entry.index;
}
entry = entry.next;
}
return addTypeInternal(
new Symbol(typeCount, UNINITIALIZED_TYPE_TAG, null, null, value, bytecodeOffset, hashCode));
}
int addMergedType(final int typeTableIndex1, final int typeTableIndex2) {
final int MERGED_TYPE_TAG = 130;
long data =
typeTableIndex1 < typeTableIndex2
? typeTableIndex1 | (((long) typeTableIndex2) << 32)
: typeTableIndex2 | (((long) typeTableIndex1) << 32);
int hashCode = 0x7FFFFFFF & (MERGED_TYPE_TAG + typeTableIndex1 + typeTableIndex2);
Symbol entry = entries[hashCode % entries.length];
while (entry != null) {
if (entry.tag == 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 Symbol(typeCount, MERGED_TYPE_TAG, null, null, null, data, hashCode)).info = commonSuperTypeIndex;
return commonSuperTypeIndex;
}
private int addTypeInternal(final Symbol entry) {
if (typeTable == null) {
typeTable = new Symbol[16];
}
if (typeCount == typeTable.length) {
Symbol[] newTypeTable = new Symbol[2 * typeTable.length];
System.arraycopy(typeTable, 0, newTypeTable, 0, typeTable.length);
typeTable = newTypeTable;
}
typeTable[typeCount++] = entry;
return put(entry).index;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy