Upgrade to ASM master (including early support for Java 22 bytecode)
Closes gh-30845
This commit is contained in:
parent
3a8b5111d9
commit
0d8a8432d1
|
|
@ -194,7 +194,7 @@ public class ClassReader {
|
|||
this.b = classFileBuffer;
|
||||
// Check the class' major_version. This field is after the magic and minor_version fields, which
|
||||
// use 4 and 2 bytes respectively.
|
||||
if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V21) {
|
||||
if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V22) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported class file major version " + readShort(classFileOffset + 6));
|
||||
}
|
||||
|
|
@ -2052,6 +2052,7 @@ public class ClassReader {
|
|||
currentOffset = bytecodeStartOffset;
|
||||
while (currentOffset < bytecodeEndOffset) {
|
||||
final int currentBytecodeOffset = currentOffset - bytecodeStartOffset;
|
||||
readBytecodeInstructionOffset(currentBytecodeOffset);
|
||||
|
||||
// Visit the label and the line number(s) for this bytecode offset, if any.
|
||||
Label currentLabel = labels[currentBytecodeOffset];
|
||||
|
|
@ -2667,6 +2668,20 @@ public class ClassReader {
|
|||
methodVisitor.visitMaxs(maxStack, maxLocals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the bytecode offset of the next instruction to be visited in {@link
|
||||
* #accept(ClassVisitor,int)}. This method is called just before the instruction and before its
|
||||
* associated label and stack map frame, if any. The default implementation of this method does
|
||||
* nothing. Subclasses can override this method to store the argument in a mutable field, for
|
||||
* instance, so that {@link MethodVisitor} instances can get the bytecode offset of each visited
|
||||
* instruction (if so, the usual concurrency issues related to mutable data should be addressed).
|
||||
*
|
||||
* @param bytecodeOffset the bytecode offset of the next instruction to be visited.
|
||||
*/
|
||||
protected void readBytecodeInstructionOffset(final int bytecodeOffset) {
|
||||
// Do nothing by default.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the label corresponding to the given bytecode offset. The default implementation of
|
||||
* this method creates a label for the given offset if it has not been already created.
|
||||
|
|
|
|||
|
|
@ -217,6 +217,7 @@ public class ClassWriter extends ClassVisitor {
|
|||
/**
|
||||
* Indicates what must be automatically computed in {@link MethodWriter}. Must be one of {@link
|
||||
* MethodWriter#COMPUTE_NOTHING}, {@link MethodWriter#COMPUTE_MAX_STACK_AND_LOCAL}, {@link
|
||||
* MethodWriter#COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES}, {@link
|
||||
* MethodWriter#COMPUTE_INSERTED_FRAMES}, or {@link MethodWriter#COMPUTE_ALL_FRAMES}.
|
||||
*/
|
||||
private int compute;
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ package org.springframework.asm;
|
|||
* right shift of {@link #DIM_SHIFT}.
|
||||
* <li>the KIND field, stored in 4 bits, indicates the kind of VALUE used. These 4 bits can be
|
||||
* retrieved with {@link #KIND_MASK} and, without any shift, must be equal to {@link
|
||||
* #CONSTANT_KIND}, {@link #REFERENCE_KIND}, {@link #UNINITIALIZED_KIND}, {@link #LOCAL_KIND}
|
||||
* or {@link #STACK_KIND}.
|
||||
* #CONSTANT_KIND}, {@link #REFERENCE_KIND}, {@link #UNINITIALIZED_KIND}, {@link
|
||||
* #FORWARD_UNINITIALIZED_KIND},{@link #LOCAL_KIND} or {@link #STACK_KIND}.
|
||||
* <li>the FLAGS field, stored in 2 bits, contains up to 2 boolean flags. Currently only one flag
|
||||
* is defined, namely {@link #TOP_IF_LONG_OR_DOUBLE_FLAG}.
|
||||
* <li>the VALUE field, stored in the remaining 20 bits, contains either
|
||||
|
|
@ -78,7 +78,10 @@ package org.springframework.asm;
|
|||
* <li>the index of a {@link Symbol#TYPE_TAG} {@link Symbol} in the type table of a {@link
|
||||
* SymbolTable}, if KIND is equal to {@link #REFERENCE_KIND}.
|
||||
* <li>the index of an {@link Symbol#UNINITIALIZED_TYPE_TAG} {@link Symbol} in the type
|
||||
* table of a SymbolTable, if KIND is equal to {@link #UNINITIALIZED_KIND}.
|
||||
* table of a {@link SymbolTable}, if KIND is equal to {@link #UNINITIALIZED_KIND}.
|
||||
* <li>the index of a {@link Symbol#FORWARD_UNINITIALIZED_TYPE_TAG} {@link Symbol} in the
|
||||
* type table of a {@link SymbolTable}, if KIND is equal to {@link
|
||||
* #FORWARD_UNINITIALIZED_KIND}.
|
||||
* <li>the index of a local variable in the input stack frame, if KIND is equal to {@link
|
||||
* #LOCAL_KIND}.
|
||||
* <li>a position relatively to the top of the stack of the input stack frame, if KIND is
|
||||
|
|
@ -88,10 +91,10 @@ package org.springframework.asm;
|
|||
*
|
||||
* <p>Output frames can contain abstract types of any kind and with a positive or negative array
|
||||
* dimension (and even unassigned types, represented by 0 - which does not correspond to any valid
|
||||
* abstract type value). Input frames can only contain CONSTANT_KIND, REFERENCE_KIND or
|
||||
* UNINITIALIZED_KIND abstract types of positive or {@literal null} array dimension. In all cases
|
||||
* the type table contains only internal type names (array type descriptors are forbidden - array
|
||||
* dimensions must be represented through the DIM field).
|
||||
* abstract type value). Input frames can only contain CONSTANT_KIND, REFERENCE_KIND,
|
||||
* UNINITIALIZED_KIND or FORWARD_UNINITIALIZED_KIND abstract types of positive or {@literal null}
|
||||
* array dimension. In all cases the type table contains only internal type names (array type
|
||||
* descriptors are forbidden - array dimensions must be represented through the DIM field).
|
||||
*
|
||||
* <p>The LONG and DOUBLE types are always represented by using two slots (LONG + TOP or DOUBLE +
|
||||
* TOP), for local variables as well as in the operand stack. This is necessary to be able to
|
||||
|
|
@ -159,8 +162,9 @@ class Frame {
|
|||
private static final int CONSTANT_KIND = 1 << KIND_SHIFT;
|
||||
private static final int REFERENCE_KIND = 2 << KIND_SHIFT;
|
||||
private static final int UNINITIALIZED_KIND = 3 << KIND_SHIFT;
|
||||
private static final int LOCAL_KIND = 4 << KIND_SHIFT;
|
||||
private static final int STACK_KIND = 5 << KIND_SHIFT;
|
||||
private static final int FORWARD_UNINITIALIZED_KIND = 4 << KIND_SHIFT;
|
||||
private static final int LOCAL_KIND = 5 << KIND_SHIFT;
|
||||
private static final int STACK_KIND = 6 << KIND_SHIFT;
|
||||
|
||||
// Possible flags for the FLAGS field of an abstract type.
|
||||
|
||||
|
|
@ -220,13 +224,13 @@ class Frame {
|
|||
|
||||
/**
|
||||
* The abstract types that are initialized in the basic block. A constructor invocation on an
|
||||
* UNINITIALIZED or UNINITIALIZED_THIS abstract type must replace <i>every occurrence</i> of this
|
||||
* type in the local variables and in the operand stack. This cannot be done during the first step
|
||||
* of the algorithm since, during this step, the local variables and the operand stack types are
|
||||
* still abstract. It is therefore necessary to store the abstract types of the constructors which
|
||||
* are invoked in the basic block, in order to do this replacement during the second step of the
|
||||
* algorithm, where the frames are fully computed. Note that this array can contain abstract types
|
||||
* that are relative to the input locals or to the input stack.
|
||||
* UNINITIALIZED, FORWARD_UNINITIALIZED or UNINITIALIZED_THIS abstract type must replace <i>every
|
||||
* occurrence</i> of this type in the local variables and in the operand stack. This cannot be
|
||||
* done during the first step of the algorithm since, during this step, the local variables and
|
||||
* the operand stack types are still abstract. It is therefore necessary to store the abstract
|
||||
* types of the constructors which are invoked in the basic block, in order to do this replacement
|
||||
* during the second step of the algorithm, where the frames are fully computed. Note that this
|
||||
* array can contain abstract types that are relative to the input locals or to the input stack.
|
||||
*/
|
||||
private int[] initializations;
|
||||
|
||||
|
|
@ -284,8 +288,12 @@ class Frame {
|
|||
String descriptor = Type.getObjectType((String) type).getDescriptor();
|
||||
return getAbstractTypeFromDescriptor(symbolTable, descriptor, 0);
|
||||
} else {
|
||||
return UNINITIALIZED_KIND
|
||||
| symbolTable.addUninitializedType("", ((Label) type).bytecodeOffset);
|
||||
Label label = (Label) type;
|
||||
if ((label.flags & Label.FLAG_RESOLVED) != 0) {
|
||||
return UNINITIALIZED_KIND | symbolTable.addUninitializedType("", label.bytecodeOffset);
|
||||
} else {
|
||||
return FORWARD_UNINITIALIZED_KIND | symbolTable.addForwardUninitializedType("", label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -637,12 +645,14 @@ class Frame {
|
|||
* @param symbolTable the type table to use to lookup and store type {@link Symbol}.
|
||||
* @param abstractType an abstract type.
|
||||
* @return the REFERENCE_KIND abstract type corresponding to abstractType if it is
|
||||
* UNINITIALIZED_THIS or an UNINITIALIZED_KIND abstract type for one of the types on which a
|
||||
* constructor is invoked in the basic block. Otherwise returns abstractType.
|
||||
* UNINITIALIZED_THIS or an UNINITIALIZED_KIND or FORWARD_UNINITIALIZED_KIND abstract type for
|
||||
* one of the types on which a constructor is invoked in the basic block. Otherwise returns
|
||||
* abstractType.
|
||||
*/
|
||||
private int getInitializedType(final SymbolTable symbolTable, final int abstractType) {
|
||||
if (abstractType == UNINITIALIZED_THIS
|
||||
|| (abstractType & (DIM_MASK | KIND_MASK)) == UNINITIALIZED_KIND) {
|
||||
|| (abstractType & (DIM_MASK | KIND_MASK)) == UNINITIALIZED_KIND
|
||||
|| (abstractType & (DIM_MASK | KIND_MASK)) == FORWARD_UNINITIALIZED_KIND) {
|
||||
for (int i = 0; i < initializationCount; ++i) {
|
||||
int initializedType = initializations[i];
|
||||
int dim = initializedType & DIM_MASK;
|
||||
|
|
@ -1253,11 +1263,12 @@ class Frame {
|
|||
*
|
||||
* @param symbolTable the type table to use to lookup and store type {@link Symbol}.
|
||||
* @param sourceType the abstract type with which the abstract type array element must be merged.
|
||||
* This type should be of {@link #CONSTANT_KIND}, {@link #REFERENCE_KIND} or {@link
|
||||
* #UNINITIALIZED_KIND} kind, with positive or {@literal null} array dimensions.
|
||||
* This type should be of {@link #CONSTANT_KIND}, {@link #REFERENCE_KIND}, {@link
|
||||
* #UNINITIALIZED_KIND} or {@link #FORWARD_UNINITIALIZED_KIND} kind, with positive or
|
||||
* {@literal null} array dimensions.
|
||||
* @param dstTypes an array of abstract types. These types should be of {@link #CONSTANT_KIND},
|
||||
* {@link #REFERENCE_KIND} or {@link #UNINITIALIZED_KIND} kind, with positive or {@literal
|
||||
* null} array dimensions.
|
||||
* {@link #REFERENCE_KIND}, {@link #UNINITIALIZED_KIND} or {@link #FORWARD_UNINITIALIZED_KIND}
|
||||
* kind, with positive or {@literal null} array dimensions.
|
||||
* @param dstIndex the index of the type that must be merged in dstTypes.
|
||||
* @return {@literal true} if the type array has been modified by this operation.
|
||||
*/
|
||||
|
|
@ -1400,7 +1411,8 @@ class Frame {
|
|||
*
|
||||
* @param symbolTable the type table to use to lookup and store type {@link Symbol}.
|
||||
* @param abstractType an abstract type, restricted to {@link Frame#CONSTANT_KIND}, {@link
|
||||
* Frame#REFERENCE_KIND} or {@link Frame#UNINITIALIZED_KIND} types.
|
||||
* Frame#REFERENCE_KIND}, {@link Frame#UNINITIALIZED_KIND} or {@link
|
||||
* Frame#FORWARD_UNINITIALIZED_KIND} types.
|
||||
* @param output where the abstract type must be put.
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.4">JVMS
|
||||
* 4.7.4</a>
|
||||
|
|
@ -1422,6 +1434,10 @@ class Frame {
|
|||
case UNINITIALIZED_KIND:
|
||||
output.putByte(ITEM_UNINITIALIZED).putShort((int) symbolTable.getType(typeValue).data);
|
||||
break;
|
||||
case FORWARD_UNINITIALIZED_KIND:
|
||||
output.putByte(ITEM_UNINITIALIZED);
|
||||
symbolTable.getForwardUninitializedLabel(typeValue).put(output);
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,9 @@ public class Label {
|
|||
/** A flag indicating that the basic block corresponding to a label is the end of a subroutine. */
|
||||
static final int FLAG_SUBROUTINE_END = 64;
|
||||
|
||||
/** A flag indicating that this label has at least one associated line number. */
|
||||
static final int FLAG_LINE_NUMBER = 128;
|
||||
|
||||
/**
|
||||
* The number of elements to add to the {@link #otherLineNumbers} array when it needs to be
|
||||
* resized to store a new source line number.
|
||||
|
|
@ -113,6 +116,13 @@ public class Label {
|
|||
*/
|
||||
static final int FORWARD_REFERENCE_TYPE_WIDE = 0x20000000;
|
||||
|
||||
/**
|
||||
* The type of forward references stored in two bytes in the <i>stack map table</i>. This is the
|
||||
* case of the labels of {@link Frame#ITEM_UNINITIALIZED} stack map frame elements, when the NEW
|
||||
* instruction is after the <init> constructor call (in bytecode offset order).
|
||||
*/
|
||||
static final int FORWARD_REFERENCE_TYPE_STACK_MAP = 0x30000000;
|
||||
|
||||
/**
|
||||
* The bit mask to extract the 'handle' of a forward reference to this label. The extracted handle
|
||||
* is the bytecode offset where the forward reference value is stored (using either 2 or 4 bytes,
|
||||
|
|
@ -145,9 +155,9 @@ public class Label {
|
|||
short flags;
|
||||
|
||||
/**
|
||||
* The source line number corresponding to this label, or 0. If there are several source line
|
||||
* numbers corresponding to this label, the first one is stored in this field, and the remaining
|
||||
* ones are stored in {@link #otherLineNumbers}.
|
||||
* The source line number corresponding to this label, if {@link #FLAG_LINE_NUMBER} is set. If
|
||||
* there are several source line numbers corresponding to this label, the first one is stored in
|
||||
* this field, and the remaining ones are stored in {@link #otherLineNumbers}.
|
||||
*/
|
||||
private short lineNumber;
|
||||
|
||||
|
|
@ -332,7 +342,8 @@ public class Label {
|
|||
* @param lineNumber a source line number (which should be strictly positive).
|
||||
*/
|
||||
final void addLineNumber(final int lineNumber) {
|
||||
if (this.lineNumber == 0) {
|
||||
if ((flags & FLAG_LINE_NUMBER) == 0) {
|
||||
flags |= FLAG_LINE_NUMBER;
|
||||
this.lineNumber = (short) lineNumber;
|
||||
} else {
|
||||
if (otherLineNumbers == null) {
|
||||
|
|
@ -356,7 +367,7 @@ public class Label {
|
|||
*/
|
||||
final void accept(final MethodVisitor methodVisitor, final boolean visitLineNumbers) {
|
||||
methodVisitor.visitLabel(this);
|
||||
if (visitLineNumbers && lineNumber != 0) {
|
||||
if (visitLineNumbers && (flags & FLAG_LINE_NUMBER) != 0) {
|
||||
methodVisitor.visitLineNumber(lineNumber & 0xFFFF, this);
|
||||
if (otherLineNumbers != null) {
|
||||
for (int i = 1; i <= otherLineNumbers[0]; ++i) {
|
||||
|
|
@ -400,6 +411,20 @@ public class Label {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a reference to this label in the <i>stack map table</i> of a method. If the bytecode
|
||||
* offset of the label is known, it is written directly. Otherwise, a null relative offset is
|
||||
* written and a new forward reference is declared for this label.
|
||||
*
|
||||
* @param stackMapTableEntries the stack map table where the label offset must be added.
|
||||
*/
|
||||
final void put(final ByteVector stackMapTableEntries) {
|
||||
if ((flags & FLAG_RESOLVED) == 0) {
|
||||
addForwardReference(0, FORWARD_REFERENCE_TYPE_STACK_MAP, stackMapTableEntries.length);
|
||||
}
|
||||
stackMapTableEntries.putShort(bytecodeOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a forward reference to this label. This method must be called only for a true forward
|
||||
* reference, i.e. only if this label is not resolved yet. For backward references, the relative
|
||||
|
|
@ -432,9 +457,12 @@ public class Label {
|
|||
* Sets the bytecode offset of this label to the given value and resolves the forward references
|
||||
* to this label, if any. This method must be called when this label is added to the bytecode of
|
||||
* the method, i.e. when its bytecode offset becomes known. This method fills in the blanks that
|
||||
* where left in the bytecode by each forward reference previously added to this label.
|
||||
* where left in the bytecode (and optionally in the stack map table) by each forward reference
|
||||
* previously added to this label.
|
||||
*
|
||||
* @param code the bytecode of the method.
|
||||
* @param stackMapTableEntries the 'entries' array of the StackMapTable code attribute of the
|
||||
* method. Maybe {@literal null}.
|
||||
* @param bytecodeOffset the bytecode offset of this label.
|
||||
* @return {@literal true} if a blank that was left for this label was too small to store the
|
||||
* offset. In such a case the corresponding jump instruction is replaced with an equivalent
|
||||
|
|
@ -442,7 +470,8 @@ public class Label {
|
|||
* instructions are later replaced with standard bytecode instructions with wider offsets (4
|
||||
* bytes instead of 2), in ClassReader.
|
||||
*/
|
||||
final boolean resolve(final byte[] code, final int bytecodeOffset) {
|
||||
final boolean resolve(
|
||||
final byte[] code, final ByteVector stackMapTableEntries, final int bytecodeOffset) {
|
||||
this.flags |= FLAG_RESOLVED;
|
||||
this.bytecodeOffset = bytecodeOffset;
|
||||
if (forwardReferences == null) {
|
||||
|
|
@ -472,11 +501,14 @@ public class Label {
|
|||
}
|
||||
code[handle++] = (byte) (relativeOffset >>> 8);
|
||||
code[handle] = (byte) relativeOffset;
|
||||
} else {
|
||||
} else if ((reference & FORWARD_REFERENCE_TYPE_MASK) == FORWARD_REFERENCE_TYPE_WIDE) {
|
||||
code[handle++] = (byte) (relativeOffset >>> 24);
|
||||
code[handle++] = (byte) (relativeOffset >>> 16);
|
||||
code[handle++] = (byte) (relativeOffset >>> 8);
|
||||
code[handle] = (byte) relativeOffset;
|
||||
} else {
|
||||
stackMapTableEntries.data[handle++] = (byte) (bytecodeOffset >>> 8);
|
||||
stackMapTableEntries.data[handle] = (byte) bytecodeOffset;
|
||||
}
|
||||
}
|
||||
return hasAsmInstructions;
|
||||
|
|
|
|||
|
|
@ -534,8 +534,9 @@ final class MethodWriter extends MethodVisitor {
|
|||
* the number of stack elements. The local variables start at index 3 and are followed by the
|
||||
* operand stack elements. In summary frame[0] = offset, frame[1] = numLocal, frame[2] = numStack.
|
||||
* Local variables and operand stack entries contain abstract types, as defined in {@link Frame},
|
||||
* but restricted to {@link Frame#CONSTANT_KIND}, {@link Frame#REFERENCE_KIND} or {@link
|
||||
* Frame#UNINITIALIZED_KIND} abstract types. Long and double types use only one array entry.
|
||||
* but restricted to {@link Frame#CONSTANT_KIND}, {@link Frame#REFERENCE_KIND}, {@link
|
||||
* Frame#UNINITIALIZED_KIND} or {@link Frame#FORWARD_UNINITIALIZED_KIND} abstract types. Long and
|
||||
* double types use only one array entry.
|
||||
*/
|
||||
private int[] currentFrame;
|
||||
|
||||
|
|
@ -1199,7 +1200,7 @@ final class MethodWriter extends MethodVisitor {
|
|||
@Override
|
||||
public void visitLabel(final Label label) {
|
||||
// Resolve the forward references to this label, if any.
|
||||
hasAsmInstructions |= label.resolve(code.data, code.length);
|
||||
hasAsmInstructions |= label.resolve(code.data, stackMapTableEntries, code.length);
|
||||
// visitLabel starts a new basic block (except for debug only labels), so we need to update the
|
||||
// previous and current block references and list of successors.
|
||||
if ((label.flags & Label.FLAG_DEBUG_ONLY) != 0) {
|
||||
|
|
@ -1795,7 +1796,7 @@ final class MethodWriter extends MethodVisitor {
|
|||
if (compute == COMPUTE_ALL_FRAMES) {
|
||||
Label nextBasicBlock = new Label();
|
||||
nextBasicBlock.frame = new Frame(nextBasicBlock);
|
||||
nextBasicBlock.resolve(code.data, code.length);
|
||||
nextBasicBlock.resolve(code.data, stackMapTableEntries, code.length);
|
||||
lastBasicBlock.nextBasicBlock = nextBasicBlock;
|
||||
lastBasicBlock = nextBasicBlock;
|
||||
currentBasicBlock = null;
|
||||
|
|
@ -1979,9 +1980,8 @@ final class MethodWriter extends MethodVisitor {
|
|||
.putByte(Frame.ITEM_OBJECT)
|
||||
.putShort(symbolTable.addConstantClass((String) type).index);
|
||||
} else {
|
||||
stackMapTableEntries
|
||||
.putByte(Frame.ITEM_UNINITIALIZED)
|
||||
.putShort(((Label) type).bytecodeOffset);
|
||||
stackMapTableEntries.putByte(Frame.ITEM_UNINITIALIZED);
|
||||
((Label) type).put(stackMapTableEntries);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -286,6 +286,7 @@ public interface Opcodes {
|
|||
int V19 = 0 << 16 | 63;
|
||||
int V20 = 0 << 16 | 64;
|
||||
int V21 = 0 << 16 | 65;
|
||||
int V22 = 0 << 16 | 66;
|
||||
|
||||
/**
|
||||
* Version flag indicating that the class is using 'preview' features.
|
||||
|
|
|
|||
|
|
@ -103,12 +103,25 @@ abstract class Symbol {
|
|||
static final int TYPE_TAG = 128;
|
||||
|
||||
/**
|
||||
* The tag value of an {@link Frame#ITEM_UNINITIALIZED} type entry in the type table of a class.
|
||||
* The tag value of an uninitialized type entry in the type table of a class. This type is used
|
||||
* for the normal case where the NEW instruction is before the <init> constructor call (in
|
||||
* bytecode offset order), i.e. when the label of the NEW instruction is resolved when the
|
||||
* constructor call is visited. If the NEW instruction is after the constructor call, use the
|
||||
* {@link #FORWARD_UNINITIALIZED_TYPE_TAG} tag value instead.
|
||||
*/
|
||||
static final int UNINITIALIZED_TYPE_TAG = 129;
|
||||
|
||||
/**
|
||||
* The tag value of an uninitialized type entry in the type table of a class. This type is used
|
||||
* for the unusual case where the NEW instruction is after the <init> constructor call (in
|
||||
* bytecode offset order), i.e. when the label of the NEW instruction is not resolved when the
|
||||
* constructor call is visited. If the NEW instruction is before the constructor call, use the
|
||||
* {@link #UNINITIALIZED_TYPE_TAG} tag value instead.
|
||||
*/
|
||||
static final int FORWARD_UNINITIALIZED_TYPE_TAG = 130;
|
||||
|
||||
/** The tag value of a merged type entry in the (ASM specific) type table of a class. */
|
||||
static final int MERGED_TYPE_TAG = 130;
|
||||
static final int MERGED_TYPE_TAG = 131;
|
||||
|
||||
// Instance fields.
|
||||
|
||||
|
|
@ -151,8 +164,8 @@ abstract class Symbol {
|
|||
* #CONSTANT_INVOKE_DYNAMIC_TAG} symbols,
|
||||
* <li>an arbitrary string for {@link #CONSTANT_UTF8_TAG} and {@link #CONSTANT_STRING_TAG}
|
||||
* symbols,
|
||||
* <li>an internal class name for {@link #CONSTANT_CLASS_TAG}, {@link #TYPE_TAG} and {@link
|
||||
* #UNINITIALIZED_TYPE_TAG} symbols,
|
||||
* <li>an internal class name for {@link #CONSTANT_CLASS_TAG}, {@link #TYPE_TAG}, {@link
|
||||
* #UNINITIALIZED_TYPE_TAG} and {@link #FORWARD_UNINITIALIZED_TYPE_TAG} symbols,
|
||||
* <li>{@literal null} for the other types of symbol.
|
||||
* </ul>
|
||||
*/
|
||||
|
|
@ -172,6 +185,9 @@ abstract class Symbol {
|
|||
* {@link #CONSTANT_DYNAMIC_TAG} or {@link #BOOTSTRAP_METHOD_TAG} symbols,
|
||||
* <li>the bytecode offset of the NEW instruction that created an {@link
|
||||
* Frame#ITEM_UNINITIALIZED} type for {@link #UNINITIALIZED_TYPE_TAG} symbols,
|
||||
* <li>the index of the {@link Label} (in the {@link SymbolTable#labelTable} table) of the NEW
|
||||
* instruction that created an {@link Frame#ITEM_UNINITIALIZED} type for {@link
|
||||
* #FORWARD_UNINITIALIZED_TYPE_TAG} symbols,
|
||||
* <li>the indices (in the class' type table) of two {@link #TYPE_TAG} source types for {@link
|
||||
* #MERGED_TYPE_TAG} symbols,
|
||||
* <li>0 for the other types of symbol.
|
||||
|
|
|
|||
|
|
@ -108,11 +108,35 @@ final class SymbolTable {
|
|||
* 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).
|
||||
* Symbol#TYPE_TAG}, {@link Symbol#UNINITIALIZED_TYPE_TAG},{@link
|
||||
* Symbol#FORWARD_UNINITIALIZED_TYPE_TAG} and {@link Symbol#MERGED_TYPE_TAG} entries. The type
|
||||
* symbol at index {@code i} has its {@link Symbol#index} equal to {@code i} (and vice versa).
|
||||
*/
|
||||
private Entry[] typeTable;
|
||||
|
||||
/**
|
||||
* The actual number of {@link LabelEntry} in {@link #labelTable}. These elements are stored from
|
||||
* index 0 to labelCount (excluded). The other array entries are empty. These label entries are
|
||||
* also stored in the {@link #labelEntries} hash set.
|
||||
*/
|
||||
private int labelCount;
|
||||
|
||||
/**
|
||||
* The labels corresponding to the "forward uninitialized" types in the ASM specific {@link
|
||||
* typeTable} (see {@link Symbol#FORWARD_UNINITIALIZED_TYPE_TAG}). The label entry at index {@code
|
||||
* i} has its {@link LabelEntry#index} equal to {@code i} (and vice versa).
|
||||
*/
|
||||
private LabelEntry[] labelTable;
|
||||
|
||||
/**
|
||||
* A hash set of all the {@link LabelEntry} elements in the {@link #labelTable}. Each {@link
|
||||
* LabelEntry} 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 LabelEntry#next} field. The {@link #getOrAddLabelEntry(Label)} method ensures that this
|
||||
* table does not contain duplicated entries.
|
||||
*/
|
||||
private LabelEntry[] labelEntries;
|
||||
|
||||
/**
|
||||
* Constructs a new, empty SymbolTable for the given ClassWriter.
|
||||
*
|
||||
|
|
@ -1129,6 +1153,18 @@ final class SymbolTable {
|
|||
return typeTable[typeIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the label corresponding to the "forward uninitialized" type table element whose index
|
||||
* is given.
|
||||
*
|
||||
* @param typeIndex the type table index of a "forward uninitialized" type table element.
|
||||
* @return the label corresponding of the NEW instruction which created this "forward
|
||||
* uninitialized" type.
|
||||
*/
|
||||
Label getForwardUninitializedLabel(final int typeIndex) {
|
||||
return labelTable[(int) typeTable[typeIndex].data].label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a type in the type table of this symbol table. Does nothing if the type table already
|
||||
* contains a similar type.
|
||||
|
|
@ -1149,13 +1185,13 @@ final class SymbolTable {
|
|||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Adds an 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.
|
||||
* @param bytecodeOffset the bytecode offset of the NEW instruction that created this
|
||||
* uninitialized type value.
|
||||
* @return the index of a new or already existing type #@link Symbol} with the given value.
|
||||
*/
|
||||
int addUninitializedType(final String value, final int bytecodeOffset) {
|
||||
int hashCode = hash(Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset);
|
||||
|
|
@ -1173,6 +1209,32 @@ final class SymbolTable {
|
|||
new Entry(typeCount, Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset, hashCode));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a "forward 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 label the label of the NEW instruction that created this uninitialized type value. If
|
||||
* the label is resolved, use the {@link #addUninitializedType} method instead.
|
||||
* @return the index of a new or already existing type {@link Symbol} with the given value.
|
||||
*/
|
||||
int addForwardUninitializedType(final String value, final Label label) {
|
||||
int labelIndex = getOrAddLabelEntry(label).index;
|
||||
int hashCode = hash(Symbol.FORWARD_UNINITIALIZED_TYPE_TAG, value, labelIndex);
|
||||
Entry entry = get(hashCode);
|
||||
while (entry != null) {
|
||||
if (entry.tag == Symbol.FORWARD_UNINITIALIZED_TYPE_TAG
|
||||
&& entry.hashCode == hashCode
|
||||
&& entry.data == labelIndex
|
||||
&& entry.value.equals(value)) {
|
||||
return entry.index;
|
||||
}
|
||||
entry = entry.next;
|
||||
}
|
||||
return addTypeInternal(
|
||||
new Entry(typeCount, Symbol.FORWARD_UNINITIALIZED_TYPE_TAG, value, labelIndex, hashCode));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a merged type in the type table of this symbol table. Does nothing if the type table
|
||||
* already contains a similar type.
|
||||
|
|
@ -1225,6 +1287,59 @@ final class SymbolTable {
|
|||
return put(entry).index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link LabelEntry} corresponding to the given label. Creates a new one if there is
|
||||
* no such entry.
|
||||
*
|
||||
* @param label the {@link Label} of a NEW instruction which created an uninitialized type, in the
|
||||
* case where this NEW instruction is after the <init> constructor call (in bytecode
|
||||
* offset order). See {@link Symbol#FORWARD_UNINITIALIZED_TYPE_TAG}.
|
||||
* @return the {@link LabelEntry} corresponding to {@code label}.
|
||||
*/
|
||||
private LabelEntry getOrAddLabelEntry(final Label label) {
|
||||
if (labelEntries == null) {
|
||||
labelEntries = new LabelEntry[16];
|
||||
labelTable = new LabelEntry[16];
|
||||
}
|
||||
int hashCode = System.identityHashCode(label);
|
||||
LabelEntry labelEntry = labelEntries[hashCode % labelEntries.length];
|
||||
while (labelEntry != null && labelEntry.label != label) {
|
||||
labelEntry = labelEntry.next;
|
||||
}
|
||||
if (labelEntry != null) {
|
||||
return labelEntry;
|
||||
}
|
||||
|
||||
if (labelCount > (labelEntries.length * 3) / 4) {
|
||||
int currentCapacity = labelEntries.length;
|
||||
int newCapacity = currentCapacity * 2 + 1;
|
||||
LabelEntry[] newLabelEntries = new LabelEntry[newCapacity];
|
||||
for (int i = currentCapacity - 1; i >= 0; --i) {
|
||||
LabelEntry currentEntry = labelEntries[i];
|
||||
while (currentEntry != null) {
|
||||
int newCurrentEntryIndex = System.identityHashCode(currentEntry.label) % newCapacity;
|
||||
LabelEntry nextEntry = currentEntry.next;
|
||||
currentEntry.next = newLabelEntries[newCurrentEntryIndex];
|
||||
newLabelEntries[newCurrentEntryIndex] = currentEntry;
|
||||
currentEntry = nextEntry;
|
||||
}
|
||||
}
|
||||
labelEntries = newLabelEntries;
|
||||
}
|
||||
if (labelCount == labelTable.length) {
|
||||
LabelEntry[] newLabelTable = new LabelEntry[2 * labelTable.length];
|
||||
System.arraycopy(labelTable, 0, newLabelTable, 0, labelTable.length);
|
||||
labelTable = newLabelTable;
|
||||
}
|
||||
|
||||
labelEntry = new LabelEntry(labelCount, label);
|
||||
int index = hashCode % labelEntries.length;
|
||||
labelEntry.next = labelEntries[index];
|
||||
labelEntries[index] = labelEntry;
|
||||
labelTable[labelCount++] = labelEntry;
|
||||
return labelEntry;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Static helper methods to compute hash codes.
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
|
@ -1275,7 +1390,7 @@ final class SymbolTable {
|
|||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
private static class Entry extends Symbol {
|
||||
private static final class Entry extends Symbol {
|
||||
|
||||
/** The hash code of this entry. */
|
||||
final int hashCode;
|
||||
|
|
@ -1319,4 +1434,30 @@ final class SymbolTable {
|
|||
this.hashCode = hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A label corresponding to a "forward uninitialized" type in the ASM specific {@link
|
||||
* SymbolTable#typeTable} (see {@link Symbol#FORWARD_UNINITIALIZED_TYPE_TAG}).
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
private static final class LabelEntry {
|
||||
|
||||
/** The index of this label entry in the {@link SymbolTable#labelTable} array. */
|
||||
final int index;
|
||||
|
||||
/** The value of this label entry. */
|
||||
final Label label;
|
||||
|
||||
/**
|
||||
* Another entry (and so on recursively) having the same hash code (modulo the size of {@link
|
||||
* SymbolTable#labelEntries}}) as this one.
|
||||
*/
|
||||
LabelEntry next;
|
||||
|
||||
LabelEntry(final int index, final Label label) {
|
||||
this.index = index;
|
||||
this.label = label;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue