All Downloads are FREE. Search and download functionalities are using the official Maven repository.

shade.com.alibaba.fastjson2.internal.asm.SymbolTable Maven / Gradle / Ivy

There is a newer version: 1.3.7
Show newest version
// 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