>
diff --git a/src/java.base/share/classes/jdk/internal/classfile/ClassfileTransform.java b/src/java.base/share/classes/jdk/internal/classfile/ClassfileTransform.java
index 3443baf94fd..299e5153835 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/ClassfileTransform.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/ClassfileTransform.java
@@ -68,6 +68,9 @@ import jdk.internal.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
*
* Complex class instrumentation sample chaining multiple transformations:
* {@snippet lang="java" class="PackageSnippets" region="classInstrumentation"}
+ * @param the transform type
+ * @param the element type
+ * @param the builder type
*/
public sealed interface ClassfileTransform<
C extends ClassfileTransform,
diff --git a/src/java.base/share/classes/jdk/internal/classfile/CodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/CodeBuilder.java
index 30534394b9d..3379e673e73 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/CodeBuilder.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/CodeBuilder.java
@@ -197,6 +197,7 @@ public sealed interface CodeBuilder
*
* @param handler handler that receives a {@linkplain BlockCodeBuilder} to
* generate the body of the lexical block.
+ * @return this builder
*/
default CodeBuilder block(Consumer handler) {
Label breakLabel = newLabel();
@@ -399,70 +400,161 @@ public sealed interface CodeBuilder
// Base convenience methods
+ /**
+ * Generate an instruction to load a value from a local variable
+ * @param tk the load type
+ * @param slot the local variable slot
+ * @return this builder
+ */
default CodeBuilder loadInstruction(TypeKind tk, int slot) {
with(LoadInstruction.of(tk, slot));
return this;
}
+ /**
+ * Generate an instruction to store a value to a local variable
+ * @param tk the store type
+ * @param slot the local variable slot
+ * @return this builder
+ */
default CodeBuilder storeInstruction(TypeKind tk, int slot) {
with(StoreInstruction.of(tk, slot));
return this;
}
+ /**
+ * Generate an instruction to increment a local variable by a constant
+ * @param slot the local variable slot
+ * @param val the increment value
+ * @return this builder
+ */
default CodeBuilder incrementInstruction(int slot, int val) {
with(IncrementInstruction.of(slot, val));
return this;
}
+ /**
+ * Generate a branch instruction
+ * @see Opcode.Kind#BRANCH
+ * @param op the branch opcode
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder branchInstruction(Opcode op, Label target) {
with(BranchInstruction.of(op, target));
return this;
}
+ /**
+ * Generate an instruction to access a jump table by key match and jump
+ * @param defaultTarget the default jump target
+ * @param cases the switch cases
+ * @return this builder
+ */
default CodeBuilder lookupSwitchInstruction(Label defaultTarget, List cases) {
with(LookupSwitchInstruction.of(defaultTarget, cases));
return this;
}
+ /**
+ * Generate an instruction to access a jump table by index and jump
+ * @param lowValue the low key value
+ * @param highValue the high key value
+ * @param defaultTarget the default jump target
+ * @param cases the switch cases
+ * @return this builder
+ */
default CodeBuilder tableSwitchInstruction(int lowValue, int highValue, Label defaultTarget, List cases) {
with(TableSwitchInstruction.of(lowValue, highValue, defaultTarget, cases));
return this;
}
+ /**
+ * Generate return instruction
+ * @param tk the return type
+ * @return this builder
+ */
default CodeBuilder returnInstruction(TypeKind tk) {
with(ReturnInstruction.of(tk));
return this;
}
+ /**
+ * Generate an instruction to throw an exception or error
+ * @return this builder
+ */
default CodeBuilder throwInstruction() {
with(ThrowInstruction.of());
return this;
}
+ /**
+ * Generate an instruction to access a field
+ * @see Opcode.Kind#FIELD_ACCESS
+ * @param opcode the field access opcode
+ * @param ref the field reference
+ * @return this builder
+ */
default CodeBuilder fieldInstruction(Opcode opcode, FieldRefEntry ref) {
with(FieldInstruction.of(opcode, ref));
return this;
}
+ /**
+ * Generate an instruction to access a field
+ * @see Opcode.Kind#FIELD_ACCESS
+ * @param opcode the field access opcode
+ * @param owner the class
+ * @param name the field name
+ * @param type the field type
+ * @return this builder
+ */
default CodeBuilder fieldInstruction(Opcode opcode, ClassDesc owner, String name, ClassDesc type) {
return fieldInstruction(opcode, constantPool().fieldRefEntry(owner, name, type));
}
+ /**
+ * Generate an instruction to invoke a method or constructor
+ * @see Opcode.Kind#INVOKE
+ * @param opcode the invoke opcode
+ * @param ref the interface method or method reference
+ * @return this builder
+ */
default CodeBuilder invokeInstruction(Opcode opcode, MemberRefEntry ref) {
return with(InvokeInstruction.of(opcode, ref));
}
+ /**
+ * Generate an instruction to invoke a method or constructor
+ * @see Opcode.Kind#INVOKE
+ * @param opcode the invoke opcode
+ * @param owner the class
+ * @param name the method name
+ * @param desc the method type
+ * @param isInterface the interface method invocation indication
+ * @return this builder
+ */
default CodeBuilder invokeInstruction(Opcode opcode, ClassDesc owner, String name, MethodTypeDesc desc, boolean isInterface) {
return invokeInstruction(opcode,
isInterface ? constantPool().interfaceMethodRefEntry(owner, name, desc)
: constantPool().methodRefEntry(owner, name, desc));
}
+ /**
+ * Generate an instruction to invoke a dynamically-computed call site
+ * @param ref the dynamic call site
+ * @return this builder
+ */
default CodeBuilder invokeDynamicInstruction(InvokeDynamicEntry ref) {
with(InvokeDynamicInstruction.of(ref));
return this;
}
+ /**
+ * Generate an instruction to invoke a dynamically-computed call site
+ * @param desc the dynamic call site
+ * @return this builder
+ */
default CodeBuilder invokeDynamicInstruction(DynamicCallSiteDesc desc) {
MethodHandleEntry bsMethod = handleDescToHandleInfo(constantPool(), (DirectMethodHandleDesc) desc.bootstrapMethod());
var cpArgs = desc.bootstrapArgs();
@@ -476,77 +568,163 @@ public sealed interface CodeBuilder
return this;
}
+ /**
+ * Generate an instruction to create a new object
+ * @param type the object type
+ * @return this builder
+ */
default CodeBuilder newObjectInstruction(ClassEntry type) {
with(NewObjectInstruction.of(type));
return this;
}
+ /**
+ * Generate an instruction to create a new object
+ * @param type the object type
+ * @return this builder
+ */
default CodeBuilder newObjectInstruction(ClassDesc type) {
return newObjectInstruction(constantPool().classEntry(type));
}
+ /**
+ * Generate an instruction to create a new array of a primitive type
+ * @param typeKind the primitive component type
+ * @return this builder
+ */
default CodeBuilder newPrimitiveArrayInstruction(TypeKind typeKind) {
with(NewPrimitiveArrayInstruction.of(typeKind));
return this;
}
+ /**
+ * Generate an instruction to create a new array of reference
+ * @param type the component type
+ * @return this builder
+ */
default CodeBuilder newReferenceArrayInstruction(ClassEntry type) {
with(NewReferenceArrayInstruction.of(type));
return this;
}
+ /**
+ * Generate an instruction to create a new array of reference
+ * @param type the component type
+ * @return this builder
+ */
default CodeBuilder newReferenceArrayInstruction(ClassDesc type) {
return newReferenceArrayInstruction(constantPool().classEntry(type));
}
+ /**
+ * Generate an instruction to create a new multidimensional array
+ * @param dimensions the number of dimensions
+ * @param type the array type
+ * @return this builder
+ */
default CodeBuilder newMultidimensionalArrayInstruction(int dimensions,
ClassEntry type) {
with(NewMultiArrayInstruction.of(type, dimensions));
return this;
}
+ /**
+ * Generate an instruction to create a new multidimensional array
+ * @param dimensions the number of dimensions
+ * @param type the array type
+ * @return this builder
+ */
default CodeBuilder newMultidimensionalArrayInstruction(int dimensions,
ClassDesc type) {
return newMultidimensionalArrayInstruction(dimensions, constantPool().classEntry(type));
}
+ /**
+ * Generate an instruction to load from an array
+ * @param tk the array element type
+ * @return this builder
+ */
default CodeBuilder arrayLoadInstruction(TypeKind tk) {
Opcode opcode = BytecodeHelpers.arrayLoadOpcode(tk);
with(ArrayLoadInstruction.of(opcode));
return this;
}
+ /**
+ * Generate an instruction to store into an array
+ * @param tk the array element type
+ * @return this builder
+ */
default CodeBuilder arrayStoreInstruction(TypeKind tk) {
Opcode opcode = BytecodeHelpers.arrayStoreOpcode(tk);
with(ArrayStoreInstruction.of(opcode));
return this;
}
+ /**
+ * Generate a type checking instruction
+ * @see Opcode.Kind#TYPE_CHECK
+ * @param opcode the type check instruction opcode
+ * @param type the type
+ * @return this builder
+ */
default CodeBuilder typeCheckInstruction(Opcode opcode,
ClassEntry type) {
with(TypeCheckInstruction.of(opcode, type));
return this;
}
+ /**
+ * Generate a type checking instruction
+ * @see Opcode.Kind#TYPE_CHECK
+ * @param opcode the type check instruction opcode
+ * @param type the type
+ * @return this builder
+ */
default CodeBuilder typeCheckInstruction(Opcode opcode, ClassDesc type) {
return typeCheckInstruction(opcode, constantPool().classEntry(type));
}
+ /**
+ * Generate a type converting instruction
+ * @param fromType the source type
+ * @param toType the target type
+ * @return this builder
+ */
default CodeBuilder convertInstruction(TypeKind fromType, TypeKind toType) {
with(ConvertInstruction.of(fromType, toType));
return this;
}
+ /**
+ * Generate a stack manipulating instruction
+ * @param opcode the stack instruction opcode
+ * @see Opcode.Kind#STACK
+ * @return this builder
+ */
default CodeBuilder stackInstruction(Opcode opcode) {
with(StackInstruction.of(opcode));
return this;
}
+ /**
+ * Generate an operator instruction
+ * @see Opcode.Kind#OPERATOR
+ * @param opcode the operator instruction opcode
+ * @return this builder
+ */
default CodeBuilder operatorInstruction(Opcode opcode) {
with(OperatorInstruction.of(opcode));
return this;
}
+ /**
+ * Generate an instruction pushing a constant onto the operand stack
+ * @see Opcode.Kind#CONSTANT
+ * @param opcode the constant instruction opcode
+ * @param value the constant value
+ * @return this builder
+ */
default CodeBuilder constantInstruction(Opcode opcode, ConstantDesc value) {
BytecodeHelpers.validateValue(opcode, value);
return with(switch (opcode) {
@@ -556,6 +734,11 @@ public sealed interface CodeBuilder
});
}
+ /**
+ * Generate an instruction pushing a constant onto the operand stack
+ * @param value the constant value
+ * @return this builder
+ */
default CodeBuilder constantInstruction(ConstantDesc value) {
//avoid switch expressions here
if (value == null || value == ConstantDescs.NULL)
@@ -586,72 +769,157 @@ public sealed interface CodeBuilder
return Double.doubleToRawLongBits(dVal) == 0l ? dconst_0()
: dVal == 1.0d ? dconst_1()
: ldc(constantPool().doubleEntry(dVal));
- return ldc(BytecodeHelpers.constantEntry(constantPool(), value));
+ return ldc(value);
}
+ /**
+ * Generate a monitor instruction
+ * @see Opcode.Kind#MONITOR
+ * @param opcode the monitor instruction opcode
+ * @return this builder
+ */
default CodeBuilder monitorInstruction(Opcode opcode) {
with(MonitorInstruction.of(opcode));
return null;
}
+ /**
+ * Generate a do nothing instruction
+ * @return this builder
+ */
default CodeBuilder nopInstruction() {
with(NopInstruction.of());
return this;
}
-
+ /**
+ * Generate a do nothing instruction
+ * @return this builder
+ */
default CodeBuilder nop() {
return nopInstruction();
}
// Base pseudo-instruction builder methods
+ /**
+ * Create new label bound with current position
+ * @return this builder
+ */
default Label newBoundLabel() {
var label = newLabel();
labelBinding(label);
return label;
}
+ /**
+ * Bind label with current position
+ * @param label the label
+ * @return this builder
+ */
default CodeBuilder labelBinding(Label label) {
with((LabelImpl) label);
return this;
}
+ /**
+ * Declare a source line number of the current builder position
+ * @param line the line number
+ * @return this builder
+ */
default CodeBuilder lineNumber(int line) {
with(LineNumber.of(line));
return this;
}
+ /**
+ * Declare an exception table entry
+ * @param start the try block start
+ * @param end the try block end
+ * @param handler the exception handler start
+ * @param catchType the catch type or null to catch all exceptions and errors
+ * @return this builder
+ */
default CodeBuilder exceptionCatch(Label start, Label end, Label handler, ClassEntry catchType) {
with(ExceptionCatch.of(handler, start, end, Optional.of(catchType)));
return this;
}
+ /**
+ * Declare an exception table entry
+ * @param start the try block start
+ * @param end the try block end
+ * @param handler the exception handler start
+ * @param catchType the optional catch type, empty to catch all exceptions and errors
+ * @return this builder
+ */
default CodeBuilder exceptionCatch(Label start, Label end, Label handler, Optional catchType) {
with(ExceptionCatch.of(handler, start, end, catchType));
return this;
}
+ /**
+ * Declare an exception table entry
+ * @param start the try block start
+ * @param end the try block end
+ * @param handler the exception handler start
+ * @param catchType the catch type
+ * @return this builder
+ */
default CodeBuilder exceptionCatch(Label start, Label end, Label handler, ClassDesc catchType) {
requireNonNull(catchType);
return exceptionCatch(start, end, handler, constantPool().classEntry(catchType));
}
+ /**
+ * Declare an exception table entry catching all exceptions and errors
+ * @param start the try block start
+ * @param end the try block end
+ * @param handler the exception handler start
+ * @return this builder
+ */
default CodeBuilder exceptionCatchAll(Label start, Label end, Label handler) {
with(ExceptionCatch.of(handler, start, end));
return this;
}
+ /**
+ * Declare a character range entry
+ * @param startScope the start scope of the character range
+ * @param endScope the end scope of the character range
+ * @param characterRangeStart the encoded start of the character range region (inclusive)
+ * @param characterRangeEnd the encoded end of the character range region (exclusive)
+ * @param flags the flags word, indicating the kind of range
+ * @return this builder
+ */
default CodeBuilder characterRange(Label startScope, Label endScope, int characterRangeStart, int characterRangeEnd, int flags) {
with(CharacterRange.of(startScope, endScope, characterRangeStart, characterRangeEnd, flags));
return this;
}
+ /**
+ * Declare a local variable entry
+ * @param slot the local variable slot
+ * @param nameEntry the variable name
+ * @param descriptorEntry the variable descriptor
+ * @param startScope the start scope of the variable
+ * @param endScope the end scope of the variable
+ * @return this builder
+ */
default CodeBuilder localVariable(int slot, Utf8Entry nameEntry, Utf8Entry descriptorEntry, Label startScope, Label endScope) {
with(LocalVariable.of(slot, nameEntry, descriptorEntry, startScope, endScope));
return this;
}
+ /**
+ * Declare a local variable entry
+ * @param slot the local variable slot
+ * @param name the variable name
+ * @param descriptor the variable descriptor
+ * @param startScope the start scope of the variable
+ * @param endScope the end scope of the variable
+ * @return this builder
+ */
default CodeBuilder localVariable(int slot, String name, ClassDesc descriptor, Label startScope, Label endScope) {
return localVariable(slot,
constantPool().utf8Entry(name),
@@ -659,11 +927,29 @@ public sealed interface CodeBuilder
startScope, endScope);
}
+ /**
+ * Declare a local variable type entry
+ * @param slot the local variable slot
+ * @param nameEntry the variable name
+ * @param signatureEntry the variable signature
+ * @param startScope the start scope of the variable
+ * @param endScope the end scope of the variable
+ * @return this builder
+ */
default CodeBuilder localVariableType(int slot, Utf8Entry nameEntry, Utf8Entry signatureEntry, Label startScope, Label endScope) {
with(LocalVariableType.of(slot, nameEntry, signatureEntry, startScope, endScope));
return this;
}
+ /**
+ * Declare a local variable type entry
+ * @param slot the local variable slot
+ * @param name the variable name
+ * @param signature the variable signature
+ * @param startScope the start scope of the variable
+ * @param endScope the end scope of the variable
+ * @return this builder
+ */
default CodeBuilder localVariableType(int slot, String name, Signature signature, Label startScope, Label endScope) {
return localVariableType(slot,
constantPool().utf8Entry(name),
@@ -673,566 +959,1219 @@ public sealed interface CodeBuilder
// Bytecode conveniences
+ /**
+ * Generate an instruction pushing the null object reference onto the operand stack
+ * @return this builder
+ */
default CodeBuilder aconst_null() {
return with(ConstantInstruction.ofIntrinsic(Opcode.ACONST_NULL));
}
+ /**
+ * Generate an instruction to load a reference from an array
+ * @return this builder
+ */
default CodeBuilder aaload() {
return arrayLoadInstruction(TypeKind.ReferenceType);
}
+ /**
+ * Generate an instruction to store into a reference array
+ * @return this builder
+ */
default CodeBuilder aastore() {
return arrayStoreInstruction(TypeKind.ReferenceType);
}
+ /**
+ * Generate an instruction to load a reference from a local variable
+ * @param slot the local variable slot
+ * @return this builder
+ */
default CodeBuilder aload(int slot) {
return loadInstruction(TypeKind.ReferenceType, slot);
}
+ /**
+ * Generate an instruction to create a new array of reference
+ * @param classEntry the component type
+ * @return this builder
+ */
default CodeBuilder anewarray(ClassEntry classEntry) {
return newReferenceArrayInstruction(classEntry);
}
+ /**
+ * Generate an instruction to create a new array of reference
+ * @param className the component type
+ * @return this builder
+ */
default CodeBuilder anewarray(ClassDesc className) {
return newReferenceArrayInstruction(constantPool().classEntry(className));
}
+ /**
+ * Generate an instruction to return a reference from the method
+ * @return this builder
+ */
default CodeBuilder areturn() {
return returnInstruction(TypeKind.ReferenceType);
}
+ /**
+ * Generate an instruction to get length of an array
+ * @return this builder
+ */
default CodeBuilder arraylength() {
return operatorInstruction(Opcode.ARRAYLENGTH);
}
+ /**
+ * Generate an instruction to store a reference into a local variable
+ * @param slot the local variable slot
+ * @return this builder
+ */
default CodeBuilder astore(int slot) {
return storeInstruction(TypeKind.ReferenceType, slot);
}
+ /**
+ * Generate an instruction to throw an exception or error
+ * @return this builder
+ */
default CodeBuilder athrow() {
return throwInstruction();
}
+ /**
+ * Generate an instruction to load a byte from a array
+ * @return this builder
+ */
default CodeBuilder baload() {
return arrayLoadInstruction(TypeKind.ByteType);
}
+ /**
+ * Generate an instruction to store into a byte array
+ * @return this builder
+ */
default CodeBuilder bastore() {
return arrayStoreInstruction(TypeKind.ByteType);
}
+ /**
+ * Generate an instruction pushing a byte onto the operand stack
+ * @param b the byte
+ * @return this builder
+ */
default CodeBuilder bipush(int b) {
return constantInstruction(Opcode.BIPUSH, b);
}
+ /**
+ * Generate an instruction to load a char from an array
+ * @return this builder
+ */
default CodeBuilder caload() {
return arrayLoadInstruction(TypeKind.CharType);
}
+ /**
+ * Generate an instruction to store into a char array
+ * @return this builder
+ */
default CodeBuilder castore() {
return arrayStoreInstruction(TypeKind.CharType);
}
+ /**
+ * Generate an instruction to check whether an object is of the given type
+ * @param type the object type
+ * @return this builder
+ */
default CodeBuilder checkcast(ClassEntry type) {
return typeCheckInstruction(Opcode.CHECKCAST, type);
}
+ /**
+ * Generate an instruction to check whether an object is of the given type
+ * @param type the object type
+ * @return this builder
+ */
default CodeBuilder checkcast(ClassDesc type) {
return typeCheckInstruction(Opcode.CHECKCAST, type);
}
+ /**
+ * Generate an instruction to convert a double into a float
+ * @return this builder
+ */
default CodeBuilder d2f() {
return convertInstruction(TypeKind.DoubleType, TypeKind.FloatType);
}
+ /**
+ * Generate an instruction to convert a double into an int
+ * @return this builder
+ */
default CodeBuilder d2i() {
return convertInstruction(TypeKind.DoubleType, TypeKind.IntType);
}
+ /**
+ * Generate an instruction to convert a double into a long
+ * @return this builder
+ */
default CodeBuilder d2l() {
return convertInstruction(TypeKind.DoubleType, TypeKind.LongType);
}
+ /**
+ * Generate an instruction to add a double
+ * @return this builder
+ */
default CodeBuilder dadd() {
return operatorInstruction(Opcode.DADD);
}
+ /**
+ * Generate an instruction to load a double from an array
+ * @return this builder
+ */
default CodeBuilder daload() {
return arrayLoadInstruction(TypeKind.DoubleType);
}
+ /**
+ * Generate an instruction to store into a double array
+ * @return this builder
+ */
default CodeBuilder dastore() {
return arrayStoreInstruction(TypeKind.DoubleType);
}
+ /**
+ * Generate an instruction to add a double
+ * @return this builder
+ */
default CodeBuilder dcmpg() {
return operatorInstruction(Opcode.DCMPG);
}
+ /**
+ * Generate an instruction to compare doubles
+ * @return this builder
+ */
default CodeBuilder dcmpl() {
return operatorInstruction(Opcode.DCMPL);
}
+ /**
+ * Generate an instruction pushing double constant 0 onto the operand stack
+ * @return this builder
+ */
default CodeBuilder dconst_0() {
return with(ConstantInstruction.ofIntrinsic(Opcode.DCONST_0));
}
+ /**
+ * Generate an instruction pushing double constant 1 onto the operand stack
+ * @return this builder
+ */
default CodeBuilder dconst_1() {
return with(ConstantInstruction.ofIntrinsic(Opcode.DCONST_1));
}
+ /**
+ * Generate an instruction to divide doubles
+ * @return this builder
+ */
default CodeBuilder ddiv() {
return operatorInstruction(Opcode.DDIV);
}
+ /**
+ * Generate an instruction to load a double from a local variable
+ * @param slot the local variable slot
+ * @return this builder
+ */
default CodeBuilder dload(int slot) {
return loadInstruction(TypeKind.DoubleType, slot);
}
+ /**
+ * Generate an instruction to multiply doubles
+ * @return this builder
+ */
default CodeBuilder dmul() {
return operatorInstruction(Opcode.DMUL);
}
+ /**
+ * Generate an instruction to negate a double
+ * @return this builder
+ */
default CodeBuilder dneg() {
return operatorInstruction(Opcode.DNEG);
}
+ /**
+ * Generate an instruction to calculate double remainder
+ * @return this builder
+ */
default CodeBuilder drem() {
return operatorInstruction(Opcode.DREM);
}
+ /**
+ * Generate an instruction to return a double from the method
+ * @return this builder
+ */
default CodeBuilder dreturn() {
return returnInstruction(TypeKind.DoubleType);
}
+ /**
+ * Generate an instruction to store a double into a local variable
+ * @param slot the local variable slot
+ * @return this builder
+ */
default CodeBuilder dstore(int slot) {
return storeInstruction(TypeKind.DoubleType, slot);
}
+ /**
+ * Generate an instruction to subtract doubles
+ * @return this builder
+ */
default CodeBuilder dsub() {
return operatorInstruction(Opcode.DSUB);
}
+ /**
+ * Generate an instruction to duplicate the top operand stack value
+ * @return this builder
+ */
default CodeBuilder dup() {
return stackInstruction(Opcode.DUP);
}
+ /**
+ * Generate an instruction to duplicate the top one or two operand stack value
+ * @return this builder
+ */
default CodeBuilder dup2() {
return stackInstruction(Opcode.DUP2);
}
+ /**
+ * Generate an instruction to duplicate the top one or two operand stack values and insert two or three
+ * values down
+ * @return this builder
+ */
default CodeBuilder dup2_x1() {
return stackInstruction(Opcode.DUP2_X1);
}
+ /**
+ * Generate an instruction to duplicate the top one or two operand stack values and insert two, three,
+ * or four values down
+ * @return this builder
+ */
default CodeBuilder dup2_x2() {
return stackInstruction(Opcode.DUP2_X2);
}
+ /**
+ * Generate an instruction to duplicate the top operand stack value and insert two values down
+ * @return this builder
+ */
default CodeBuilder dup_x1() {
return stackInstruction(Opcode.DUP_X1);
}
+ /**
+ * Generate an instruction to duplicate the top operand stack value and insert two or three values down
+ * @return this builder
+ */
default CodeBuilder dup_x2() {
return stackInstruction(Opcode.DUP_X2);
}
+ /**
+ * Generate an instruction to convert a float into a double
+ * @return this builder
+ */
default CodeBuilder f2d() {
return convertInstruction(TypeKind.FloatType, TypeKind.DoubleType);
}
+ /**
+ * Generate an instruction to convert a float into an int
+ * @return this builder
+ */
default CodeBuilder f2i() {
return convertInstruction(TypeKind.FloatType, TypeKind.IntType);
}
+ /**
+ * Generate an instruction to convert a float into a long
+ * @return this builder
+ */
default CodeBuilder f2l() {
return convertInstruction(TypeKind.FloatType, TypeKind.LongType);
}
+ /**
+ * Generate an instruction to add a float
+ * @return this builder
+ */
default CodeBuilder fadd() {
return operatorInstruction(Opcode.FADD);
}
+ /**
+ * Generate an instruction to load a float from an array
+ * @return this builder
+ */
default CodeBuilder faload() {
return arrayLoadInstruction(TypeKind.FloatType);
}
+ /**
+ * Generate an instruction to store into a float array
+ * @return this builder
+ */
default CodeBuilder fastore() {
return arrayStoreInstruction(TypeKind.FloatType);
}
+ /**
+ * Generate an instruction to compare floats
+ * @return this builder
+ */
default CodeBuilder fcmpg() {
return operatorInstruction(Opcode.FCMPG);
}
+ /**
+ * Generate an instruction to compare floats
+ * @return this builder
+ */
default CodeBuilder fcmpl() {
return operatorInstruction(Opcode.FCMPL);
}
+ /**
+ * Generate an instruction pushing float constant 0 onto the operand stack
+ * @return this builder
+ */
default CodeBuilder fconst_0() {
return with(ConstantInstruction.ofIntrinsic(Opcode.FCONST_0));
}
+ /**
+ * Generate an instruction pushing float constant 1 onto the operand stack
+ * @return this builder
+ */
default CodeBuilder fconst_1() {
return with(ConstantInstruction.ofIntrinsic(Opcode.FCONST_1));
}
+ /**
+ * Generate an instruction pushing float constant 2 onto the operand stack
+ * @return this builder
+ */
default CodeBuilder fconst_2() {
return with(ConstantInstruction.ofIntrinsic(Opcode.FCONST_2));
}
+ /**
+ * Generate an instruction to divide floats
+ * @return this builder
+ */
default CodeBuilder fdiv() {
return operatorInstruction(Opcode.FDIV);
}
+ /**
+ * Generate an instruction to load a float from a local variable
+ * @param slot the local variable slot
+ * @return this builder
+ */
default CodeBuilder fload(int slot) {
return loadInstruction(TypeKind.FloatType, slot);
}
+ /**
+ * Generate an instruction to multiply floats
+ * @return this builder
+ */
default CodeBuilder fmul() {
return operatorInstruction(Opcode.FMUL);
}
+ /**
+ * Generate an instruction to negate a float
+ * @return this builder
+ */
default CodeBuilder fneg() {
return operatorInstruction(Opcode.FNEG);
}
+ /**
+ * Generate an instruction to calculate floats remainder
+ * @return this builder
+ */
default CodeBuilder frem() {
return operatorInstruction(Opcode.FREM);
}
+ /**
+ * Generate an instruction to return a float from the method
+ * @return this builder
+ */
default CodeBuilder freturn() {
return returnInstruction(TypeKind.FloatType);
}
+ /**
+ * Generate an instruction to store a float into a local variable
+ * @param slot the local variable slot
+ * @return this builder
+ */
default CodeBuilder fstore(int slot) {
return storeInstruction(TypeKind.FloatType, slot);
}
+ /**
+ * Generate an instruction to subtract floats
+ * @return this builder
+ */
default CodeBuilder fsub() {
return operatorInstruction(Opcode.FSUB);
}
+ /**
+ * Generate an instruction to fetch field from an object
+ * @param ref the field reference
+ * @return this builder
+ */
default CodeBuilder getfield(FieldRefEntry ref) {
return fieldInstruction(Opcode.GETFIELD, ref);
}
+ /**
+ * Generate an instruction to fetch field from an object
+ * @param owner the owner class
+ * @param name the field name
+ * @param type the field type
+ * @return this builder
+ */
default CodeBuilder getfield(ClassDesc owner, String name, ClassDesc type) {
return fieldInstruction(Opcode.GETFIELD, owner, name, type);
}
+ /**
+ * Generate an instruction to get static field from a class
+ * @param ref the field reference
+ * @return this builder
+ */
default CodeBuilder getstatic(FieldRefEntry ref) {
return fieldInstruction(Opcode.GETSTATIC, ref);
}
+ /**
+ * Generate an instruction to get static field from a class
+ * @param owner the owner class
+ * @param name the field name
+ * @param type the field type
+ * @return this builder
+ */
default CodeBuilder getstatic(ClassDesc owner, String name, ClassDesc type) {
return fieldInstruction(Opcode.GETSTATIC, owner, name, type);
}
+ /**
+ * Generate an instruction to branch always
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder goto_(Label target) {
return branchInstruction(Opcode.GOTO, target);
}
+ /**
+ * Generate an instruction to branch always with wide index
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder goto_w(Label target) {
return branchInstruction(Opcode.GOTO_W, target);
}
+ /**
+ * Generate an instruction to convert an int into a byte
+ * @return this builder
+ */
default CodeBuilder i2b() {
return convertInstruction(TypeKind.IntType, TypeKind.ByteType);
}
+ /**
+ * Generate an instruction to convert an int into a char
+ * @return this builder
+ */
default CodeBuilder i2c() {
return convertInstruction(TypeKind.IntType, TypeKind.CharType);
}
+ /**
+ * Generate an instruction to convert an int into a double
+ * @return this builder
+ */
default CodeBuilder i2d() {
return convertInstruction(TypeKind.IntType, TypeKind.DoubleType);
}
+ /**
+ * Generate an instruction to convert an int into a float
+ * @return this builder
+ */
default CodeBuilder i2f() {
return convertInstruction(TypeKind.IntType, TypeKind.FloatType);
}
+ /**
+ * Generate an instruction to convert an int into a long
+ * @return this builder
+ */
default CodeBuilder i2l() {
return convertInstruction(TypeKind.IntType, TypeKind.LongType);
}
+ /**
+ * Generate an instruction to convert an int into a short
+ * @return this builder
+ */
default CodeBuilder i2s() {
return convertInstruction(TypeKind.IntType, TypeKind.ShortType);
}
+ /**
+ * Generate an instruction to add an int
+ * @return this builder
+ */
default CodeBuilder iadd() {
return operatorInstruction(Opcode.IADD);
}
+ /**
+ * Generate an instruction to load a int from an array
+ * @return this builder
+ */
default CodeBuilder iaload() {
return arrayLoadInstruction(TypeKind.IntType);
}
+ /**
+ * Generate an instruction to calculate boolean AND of ints
+ * @return this builder
+ */
default CodeBuilder iand() {
return operatorInstruction(Opcode.IAND);
}
+ /**
+ * Generate an instruction to store into an int array
+ * @return this builder
+ */
default CodeBuilder iastore() {
return arrayStoreInstruction(TypeKind.IntType);
}
+ /**
+ * Generate an instruction pushing int constant 0 onto the operand stack
+ * @return this builder
+ */
default CodeBuilder iconst_0() {
return with(ConstantInstruction.ofIntrinsic(Opcode.ICONST_0));
}
+ /**
+ * Generate an instruction pushing int constant 1 onto the operand stack
+ * @return this builder
+ */
default CodeBuilder iconst_1() {
return with(ConstantInstruction.ofIntrinsic(Opcode.ICONST_1));
}
+ /**
+ * Generate an instruction pushing int constant 2 onto the operand stack
+ * @return this builder
+ */
default CodeBuilder iconst_2() {
return with(ConstantInstruction.ofIntrinsic(Opcode.ICONST_2));
}
+ /**
+ * Generate an instruction pushing int constant 3 onto the operand stack
+ * @return this builder
+ */
default CodeBuilder iconst_3() {
return with(ConstantInstruction.ofIntrinsic(Opcode.ICONST_3));
}
+ /**
+ * Generate an instruction pushing int constant 4 onto the operand stack
+ * @return this builder
+ */
default CodeBuilder iconst_4() {
return with(ConstantInstruction.ofIntrinsic(Opcode.ICONST_4));
}
+ /**
+ * Generate an instruction pushing int constant 5 onto the operand stack
+ * @return this builder
+ */
default CodeBuilder iconst_5() {
return with(ConstantInstruction.ofIntrinsic(Opcode.ICONST_5));
}
+ /**
+ * Generate an instruction pushing int constant -1 onto the operand stack
+ * @return this builder
+ */
default CodeBuilder iconst_m1() {
return with(ConstantInstruction.ofIntrinsic(Opcode.ICONST_M1));
}
+ /**
+ * Generate an instruction to divide ints
+ * @return this builder
+ */
default CodeBuilder idiv() {
return operatorInstruction(Opcode.IDIV);
}
+ /**
+ * Generate an instruction to branch if int comparison succeeds
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder if_acmpeq(Label target) {
return branchInstruction(Opcode.IF_ACMPEQ, target);
}
+ /**
+ * Generate an instruction to branch if int comparison succeeds
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder if_acmpne(Label target) {
return branchInstruction(Opcode.IF_ACMPNE, target);
}
+ /**
+ * Generate an instruction to branch if int comparison succeeds
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder if_icmpeq(Label target) {
return branchInstruction(Opcode.IF_ICMPEQ, target);
}
+ /**
+ * Generate an instruction to branch if int comparison succeeds
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder if_icmpge(Label target) {
return branchInstruction(Opcode.IF_ICMPGE, target);
}
+ /**
+ * Generate an instruction to branch if int comparison succeeds
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder if_icmpgt(Label target) {
return branchInstruction(Opcode.IF_ICMPGT, target);
}
+ /**
+ * Generate an instruction to branch if int comparison succeeds
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder if_icmple(Label target) {
return branchInstruction(Opcode.IF_ICMPLE, target);
}
+ /**
+ * Generate an instruction to branch if int comparison succeeds
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder if_icmplt(Label target) {
return branchInstruction(Opcode.IF_ICMPLT, target);
}
+ /**
+ * Generate an instruction to branch if int comparison succeeds
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder if_icmpne(Label target) {
return branchInstruction(Opcode.IF_ICMPNE, target);
}
+ /**
+ * Generate an instruction to branch if reference is not null
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder if_nonnull(Label target) {
return branchInstruction(Opcode.IFNONNULL, target);
}
+ /**
+ * Generate an instruction to branch if reference is null
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder if_null(Label target) {
return branchInstruction(Opcode.IFNULL, target);
}
+ /**
+ * Generate an instruction to branch if int comparison with zero succeeds
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder ifeq(Label target) {
return branchInstruction(Opcode.IFEQ, target);
}
+ /**
+ * Generate an instruction to branch if int comparison with zero succeeds
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder ifge(Label target) {
return branchInstruction(Opcode.IFGE, target);
}
+ /**
+ * Generate an instruction to branch if int comparison with zero succeeds
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder ifgt(Label target) {
return branchInstruction(Opcode.IFGT, target);
}
+ /**
+ * Generate an instruction to branch if int comparison with zero succeeds
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder ifle(Label target) {
return branchInstruction(Opcode.IFLE, target);
}
+ /**
+ * Generate an instruction to branch if int comparison with zero succeeds
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder iflt(Label target) {
return branchInstruction(Opcode.IFLT, target);
}
+ /**
+ * Generate an instruction to branch if int comparison with zero succeeds
+ * @param target the branch target
+ * @return this builder
+ */
default CodeBuilder ifne(Label target) {
return branchInstruction(Opcode.IFNE, target);
}
+ /**
+ * Generate an instruction to increment a local variable by a constant
+ * @param slot the local variable slot
+ * @param val the increment value
+ * @return this builder
+ */
default CodeBuilder iinc(int slot, int val) {
return incrementInstruction(slot, val);
}
+ /**
+ * Generate an instruction to load an int from a local variable
+ * @param slot the local variable slot
+ * @return this builder
+ */
default CodeBuilder iload(int slot) {
return loadInstruction(TypeKind.IntType, slot);
}
+ /**
+ * Generate an instruction to multiply ints
+ * @return this builder
+ */
default CodeBuilder imul() {
return operatorInstruction(Opcode.IMUL);
}
+ /**
+ * Generate an instruction to negate an int
+ * @return this builder
+ */
default CodeBuilder ineg() {
return operatorInstruction(Opcode.INEG);
}
+ /**
+ * Generate an instruction to determine if an object is of the given type
+ * @param target the target type
+ * @return this builder
+ */
default CodeBuilder instanceof_(ClassEntry target) {
return typeCheckInstruction(Opcode.INSTANCEOF, target);
}
+ /**
+ * Generate an instruction to determine if an object is of the given type
+ * @param target the target type
+ * @return this builder
+ */
default CodeBuilder instanceof_(ClassDesc target) {
return typeCheckInstruction(Opcode.INSTANCEOF, constantPool().classEntry(target));
}
+ /**
+ * Generate an instruction to invoke a dynamically-computed call site
+ * @param ref the dynamic call site
+ * @return this builder
+ */
default CodeBuilder invokedynamic(InvokeDynamicEntry ref) {
return invokeDynamicInstruction(ref);
}
+ /**
+ * Generate an instruction to invoke a dynamically-computed call site
+ * @param ref the dynamic call site
+ * @return this builder
+ */
default CodeBuilder invokedynamic(DynamicCallSiteDesc ref) {
return invokeDynamicInstruction(ref);
}
+ /**
+ * Generate an instruction to invoke an interface method
+ * @param ref the interface method reference
+ * @return this builder
+ */
default CodeBuilder invokeinterface(InterfaceMethodRefEntry ref) {
return invokeInstruction(Opcode.INVOKEINTERFACE, ref);
}
+ /**
+ * Generate an instruction to invoke an interface method
+ * @param owner the owner class
+ * @param name the method name
+ * @param type the method type
+ * @return this builder
+ */
default CodeBuilder invokeinterface(ClassDesc owner, String name, MethodTypeDesc type) {
return invokeInstruction(Opcode.INVOKEINTERFACE, constantPool().interfaceMethodRefEntry(owner, name, type));
}
+ /**
+ * Generate an instruction to invoke an instance method; direct invocation of instance initialization
+ * methods and methods of the current class and its supertypes
+ * @param ref the interface method reference
+ * @return this builder
+ */
default CodeBuilder invokespecial(InterfaceMethodRefEntry ref) {
return invokeInstruction(Opcode.INVOKESPECIAL, ref);
}
+ /**
+ * Generate an instruction to invoke an instance method; direct invocation of instance initialization
+ * methods and methods of the current class and its supertypes
+ * @param ref the method reference
+ * @return this builder
+ */
default CodeBuilder invokespecial(MethodRefEntry ref) {
return invokeInstruction(Opcode.INVOKESPECIAL, ref);
}
+ /**
+ * Generate an instruction to invoke an instance method; direct invocation of instance initialization
+ * methods and methods of the current class and its supertypes
+ * @param owner the owner class
+ * @param name the method name
+ * @param type the method type
+ * @return this builder
+ */
default CodeBuilder invokespecial(ClassDesc owner, String name, MethodTypeDesc type) {
return invokeInstruction(Opcode.INVOKESPECIAL, owner, name, type, false);
}
+ /**
+ * Generate an instruction to invoke an instance method; direct invocation of instance initialization
+ * methods and methods of the current class and its supertypes
+ * @param owner the owner class
+ * @param name the method name
+ * @param type the method type
+ * @param isInterface the interface method invocation indication
+ * @return this builder
+ */
default CodeBuilder invokespecial(ClassDesc owner, String name, MethodTypeDesc type, boolean isInterface) {
return invokeInstruction(Opcode.INVOKESPECIAL, owner, name, type, isInterface);
}
+ /**
+ * Generate an instruction to invoke a class (static) method
+ * @param ref the interface method reference
+ * @return this builder
+ */
default CodeBuilder invokestatic(InterfaceMethodRefEntry ref) {
return invokeInstruction(Opcode.INVOKESTATIC, ref);
}
+ /**
+ * Generate an instruction to invoke a class (static) method
+ * @param ref the method reference
+ * @return this builder
+ */
default CodeBuilder invokestatic(MethodRefEntry ref) {
return invokeInstruction(Opcode.INVOKESTATIC, ref);
}
+ /**
+ * Generate an instruction to invoke a class (static) method
+ * @param owner the owner class
+ * @param name the method name
+ * @param type the method type
+ * @return this builder
+ */
default CodeBuilder invokestatic(ClassDesc owner, String name, MethodTypeDesc type) {
return invokeInstruction(Opcode.INVOKESTATIC, owner, name, type, false);
}
+ /**
+ * Generate an instruction to invoke a class (static) method
+ * @param owner the owner class
+ * @param name the method name
+ * @param type the method type
+ * @param isInterface the interface method invocation indication
+ * @return this builder
+ */
default CodeBuilder invokestatic(ClassDesc owner, String name, MethodTypeDesc type, boolean isInterface) {
return invokeInstruction(Opcode.INVOKESTATIC, owner, name, type, isInterface);
}
+ /**
+ * Generate an instruction to invoke an instance method; dispatch based on class
+ * @param ref the method reference
+ * @return this builder
+ */
default CodeBuilder invokevirtual(MethodRefEntry ref) {
return invokeInstruction(Opcode.INVOKEVIRTUAL, ref);
}
+ /**
+ * Generate an instruction to invoke an instance method; dispatch based on class
+ * @param owner the owner class
+ * @param name the method name
+ * @param type the method type
+ * @return this builder
+ */
default CodeBuilder invokevirtual(ClassDesc owner, String name, MethodTypeDesc type) {
return invokeInstruction(Opcode.INVOKEVIRTUAL, owner, name, type, false);
}
+ /**
+ * Generate an instruction to calculate boolean OR of ints
+ * @return this builder
+ */
default CodeBuilder ior() {
return operatorInstruction(Opcode.IOR);
}
+ /**
+ * Generate an instruction to calculate ints remainder
+ * @return this builder
+ */
default CodeBuilder irem() {
return operatorInstruction(Opcode.IREM);
}
+ /**
+ * Generate an instruction to return an int from the method
+ * @return this builder
+ */
default CodeBuilder ireturn() {
return returnInstruction(TypeKind.IntType);
}
+ /**
+ * Generate an instruction to shift an int left
+ * @return this builder
+ */
default CodeBuilder ishl() {
return operatorInstruction(Opcode.ISHL);
}
+ /**
+ * Generate an instruction to shift an int right
+ * @return this builder
+ */
default CodeBuilder ishr() {
return operatorInstruction(Opcode.ISHR);
}
+ /**
+ * Generate an instruction to store an int into a local variable
+ * @param slot the local variable slot
+ * @return this builder
+ */
default CodeBuilder istore(int slot) {
return storeInstruction(TypeKind.IntType, slot);
}
+ /**
+ * Generate an instruction to subtract ints
+ * @return this builder
+ */
default CodeBuilder isub() {
return operatorInstruction(Opcode.ISUB);
}
+ /**
+ * Generate an instruction to logical shift an int right
+ * @return this builder
+ */
default CodeBuilder iushr() {
return operatorInstruction(Opcode.IUSHR);
}
+ /**
+ * Generate an instruction to calculate boolean XOR of ints
+ * @return this builder
+ */
default CodeBuilder ixor() {
return operatorInstruction(Opcode.IXOR);
}
+ /**
+ * Generate an instruction to access a jump table by key match and jump
+ * @param defaultTarget the default jump target
+ * @param cases the switch cases
+ * @return this builder
+ */
default CodeBuilder lookupswitch(Label defaultTarget, List cases) {
return lookupSwitchInstruction(defaultTarget, cases);
}
+ /**
+ * Generate an instruction to convert a long into a double
+ * @return this builder
+ */
default CodeBuilder l2d() {
return convertInstruction(TypeKind.LongType, TypeKind.DoubleType);
}
+ /**
+ * Generate an instruction to convert a long into a float
+ * @return this builder
+ */
default CodeBuilder l2f() {
return convertInstruction(TypeKind.LongType, TypeKind.FloatType);
}
+ /**
+ * Generate an instruction to convert a long into an int
+ * @return this builder
+ */
default CodeBuilder l2i() {
return convertInstruction(TypeKind.LongType, TypeKind.IntType);
}
+ /**
+ * Generate an instruction to add a long
+ * @return this builder
+ */
default CodeBuilder ladd() {
return operatorInstruction(Opcode.LADD);
}
+ /**
+ * Generate an instruction to load a long from an array
+ * @return this builder
+ */
default CodeBuilder laload() {
return arrayLoadInstruction(TypeKind.LongType);
}
+ /**
+ * Generate an instruction to calculate boolean AND of longs
+ * @return this builder
+ */
default CodeBuilder land() {
return operatorInstruction(Opcode.LAND);
}
+ /**
+ * Generate an instruction to store into a long array
+ * @return this builder
+ */
default CodeBuilder lastore() {
return arrayStoreInstruction(TypeKind.LongType);
}
+ /**
+ * Generate an instruction to compare longs
+ * @return this builder
+ */
default CodeBuilder lcmp() {
return operatorInstruction(Opcode.LCMP);
}
+ /**
+ * Generate an instruction pushing long constant 0 onto the operand stack
+ * @return this builder
+ */
default CodeBuilder lconst_0() {
return with(ConstantInstruction.ofIntrinsic(Opcode.LCONST_0));
}
+ /**
+ * Generate an instruction pushing long constant 1 onto the operand stack
+ * @return this builder
+ */
default CodeBuilder lconst_1() {
return with(ConstantInstruction.ofIntrinsic(Opcode.LCONST_1));
}
+ /**
+ * Generate an instruction pushing an item from the run-time constant pool onto the operand stack
+ * @param value the constant value
+ * @return this builder
+ */
+ default CodeBuilder ldc(ConstantDesc value) {
+ return ldc(BytecodeHelpers.constantEntry(constantPool(), value));
+ }
+
+ /**
+ * Generate an instruction pushing an item from the run-time constant pool onto the operand stack
+ * @param entry the constant value
+ * @return this builder
+ */
default CodeBuilder ldc(LoadableConstantEntry entry) {
return with(ConstantInstruction.ofLoad(
entry.typeKind().slotSize() == 2 ? Opcode.LDC2_W
@@ -1240,134 +2179,290 @@ public sealed interface CodeBuilder
: Opcode.LDC, entry));
}
+ /**
+ * Generate an instruction to divide longs
+ * @return this builder
+ */
default CodeBuilder ldiv() {
return operatorInstruction(Opcode.LDIV);
}
+ /**
+ * Generate an instruction to load a long from a local variable
+ * @param slot the local variable slot
+ * @return this builder
+ */
default CodeBuilder lload(int slot) {
return loadInstruction(TypeKind.LongType, slot);
}
+ /**
+ * Generate an instruction to multiply longs
+ * @return this builder
+ */
default CodeBuilder lmul() {
return operatorInstruction(Opcode.LMUL);
}
+ /**
+ * Generate an instruction to negate a long
+ * @return this builder
+ */
default CodeBuilder lneg() {
return operatorInstruction(Opcode.LNEG);
}
+ /**
+ * Generate an instruction to calculate boolean OR of longs
+ * @return this builder
+ */
default CodeBuilder lor() {
return operatorInstruction(Opcode.LOR);
}
+ /**
+ * Generate an instruction to calculate longs remainder
+ * @return this builder
+ */
default CodeBuilder lrem() {
return operatorInstruction(Opcode.LREM);
}
+ /**
+ * Generate an instruction to return a long from the method
+ * @return this builder
+ */
default CodeBuilder lreturn() {
return returnInstruction(TypeKind.LongType);
}
+ /**
+ * Generate an instruction to shift a long left
+ * @return this builder
+ */
default CodeBuilder lshl() {
return operatorInstruction(Opcode.LSHL);
}
+ /**
+ * Generate an instruction to shift a long right
+ * @return this builder
+ */
default CodeBuilder lshr() {
return operatorInstruction(Opcode.LSHR);
}
+ /**
+ * Generate an instruction to store a long into a local variable
+ * @param slot the local variable slot
+ * @return this builder
+ */
default CodeBuilder lstore(int slot) {
return storeInstruction(TypeKind.LongType, slot);
}
+ /**
+ * Generate an instruction to subtract longs
+ * @return this builder
+ */
default CodeBuilder lsub() {
return operatorInstruction(Opcode.LSUB);
}
+ /**
+ * Generate an instruction to logical shift a long left
+ * @return this builder
+ */
default CodeBuilder lushr() {
return operatorInstruction(Opcode.LUSHR);
}
+ /**
+ * Generate an instruction to calculate boolean XOR of longs
+ * @return this builder
+ */
default CodeBuilder lxor() {
return operatorInstruction(Opcode.LXOR);
}
+ /**
+ * Generate an instruction to enter monitor for an object
+ * @return this builder
+ */
default CodeBuilder monitorenter() {
return monitorInstruction(Opcode.MONITORENTER);
}
+ /**
+ * Generate an instruction to exit monitor for an object
+ * @return this builder
+ */
default CodeBuilder monitorexit() {
return monitorInstruction(Opcode.MONITOREXIT);
}
+ /**
+ * Generate an instruction to create a new multidimensional array
+ * @param array the array type
+ * @param dims the number of dimensions
+ * @return this builder
+ */
default CodeBuilder multianewarray(ClassEntry array, int dims) {
return newMultidimensionalArrayInstruction(dims, array);
}
+ /**
+ * Generate an instruction to create a new multidimensional array
+ * @param array the array type
+ * @param dims the number of dimensions
+ * @return this builder
+ */
default CodeBuilder multianewarray(ClassDesc array, int dims) {
return newMultidimensionalArrayInstruction(dims, constantPool().classEntry(array));
}
+ /**
+ * Generate an instruction to create a new object
+ * @param clazz the new class type
+ * @return this builder
+ */
default CodeBuilder new_(ClassEntry clazz) {
return newObjectInstruction(clazz);
}
+ /**
+ * Generate an instruction to create a new object
+ * @param clazz the new class type
+ * @return this builder
+ */
default CodeBuilder new_(ClassDesc clazz) {
return newObjectInstruction(constantPool().classEntry(clazz));
}
+ /**
+ * Generate an instruction to create a new array of a primitive type
+ * @param typeKind the primitive array type
+ * @return this builder
+ */
default CodeBuilder newarray(TypeKind typeKind) {
return newPrimitiveArrayInstruction(typeKind);
}
+ /**
+ * Generate an instruction to pop the top operand stack value
+ * @return this builder
+ */
default CodeBuilder pop() {
return stackInstruction(Opcode.POP);
}
+ /**
+ * Generate an instruction to pop the top one or two operand stack values
+ * @return this builder
+ */
default CodeBuilder pop2() {
return stackInstruction(Opcode.POP2);
}
+ /**
+ * Generate an instruction to set field in an object
+ * @param ref the field reference
+ * @return this builder
+ */
default CodeBuilder putfield(FieldRefEntry ref) {
return fieldInstruction(Opcode.PUTFIELD, ref);
}
+ /**
+ * Generate an instruction to set field in an object
+ * @param owner the owner class
+ * @param name the field name
+ * @param type the field type
+ * @return this builder
+ */
default CodeBuilder putfield(ClassDesc owner, String name, ClassDesc type) {
return fieldInstruction(Opcode.PUTFIELD, owner, name, type);
}
+ /**
+ * Generate an instruction to set static field in a class
+ * @param ref the field reference
+ * @return this builder
+ */
default CodeBuilder putstatic(FieldRefEntry ref) {
return fieldInstruction(Opcode.PUTSTATIC, ref);
}
+ /**
+ * Generate an instruction to set static field in a class
+ * @param owner the owner class
+ * @param name the field name
+ * @param type the field type
+ * @return this builder
+ */
default CodeBuilder putstatic(ClassDesc owner, String name, ClassDesc type) {
return fieldInstruction(Opcode.PUTSTATIC, owner, name, type);
}
+ /**
+ * Generate an instruction to return void from the method
+ * @return this builder
+ */
default CodeBuilder return_() {
return returnInstruction(TypeKind.VoidType);
}
+ /**
+ * Generate an instruction to load a short from an array
+ * @return this builder
+ */
default CodeBuilder saload() {
return arrayLoadInstruction(TypeKind.ShortType);
}
+ /**
+ * Generate an instruction to store into a short array
+ * @return this builder
+ */
default CodeBuilder sastore() {
return arrayStoreInstruction(TypeKind.ShortType);
}
+ /**
+ * Generate an instruction pushing a short onto the operand stack
+ * @param s the short
+ * @return this builder
+ */
default CodeBuilder sipush(int s) {
return constantInstruction(Opcode.SIPUSH, s);
}
+ /**
+ * Generate an instruction to swap the top two operand stack values
+ * @return this builder
+ */
default CodeBuilder swap() {
return stackInstruction(Opcode.SWAP);
}
+ /**
+ * Generate an instruction to access a jump table by index and jump
+ * @param low the low key value
+ * @param high the high key value
+ * @param defaultTarget the default jump target
+ * @param cases the switch cases
+ * @return this builder
+ */
default CodeBuilder tableswitch(int low, int high, Label defaultTarget, List cases) {
return tableSwitchInstruction(low, high, defaultTarget, cases);
}
+ /**
+ * Generate an instruction to access a jump table by index and jump
+ * @param defaultTarget the default jump target
+ * @param cases the switch cases
+ * @return this builder
+ */
default CodeBuilder tableswitch(Label defaultTarget, List cases) {
int low = Integer.MAX_VALUE;
int high = Integer.MIN_VALUE;
@@ -1378,9 +2473,4 @@ public sealed interface CodeBuilder
}
return tableSwitchInstruction(low, high, defaultTarget, cases);
}
-
- // Structured conveniences:
-
- // allocLocal(type)
- // returnFromMethod(inferred)
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/CompoundElement.java b/src/java.base/share/classes/jdk/internal/classfile/CompoundElement.java
index 3ba7d73760b..40f85aea705 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/CompoundElement.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/CompoundElement.java
@@ -40,6 +40,7 @@ import java.util.stream.StreamSupport;
* option to treat the element as a single entity (e.g., an entire method)
* or to traverse the contents of that element with the methods in this class
* (e.g., {@link #elements()}, {@link #forEachElement(Consumer)}, etc.)
+ * @param the element type
*/
public sealed interface CompoundElement
extends ClassfileElement, Iterable
diff --git a/src/java.base/share/classes/jdk/internal/classfile/CustomAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/CustomAttribute.java
index d84e2628b9c..cd4d430403a 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/CustomAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/CustomAttribute.java
@@ -31,6 +31,7 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* this class to provide an implementation class for non-standard attributes,
* and provide an {@link AttributeMapper} to mediate between the classfile
* format and the {@linkplain CustomAttribute} representation.
+ * @param the custom attribute type
*/
@SuppressWarnings("exports")
public abstract non-sealed class CustomAttribute>
diff --git a/src/java.base/share/classes/jdk/internal/classfile/Opcode.java b/src/java.base/share/classes/jdk/internal/classfile/Opcode.java
index 6779e55448b..af1027baeca 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/Opcode.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/Opcode.java
@@ -28,237 +28,1030 @@ import java.lang.constant.ConstantDesc;
import java.lang.constant.ConstantDescs;
/**
- * Describes the opcodes of the JVM instruction set, as well as a number of
- * pseudo-instructions that may be encountered when traversing the instructions
- * of a method.
+ * Describes the opcodes of the JVM instruction set, as described in {@jvms 6.5}.
+ * As well as a number of pseudo-instructions that may be encountered when
+ * traversing the instructions of a method.
*
* @see Instruction
* @see PseudoInstruction
*/
public enum Opcode {
+
+ /** Do nothing */
NOP(Classfile.NOP, 1, Kind.NOP),
+
+ /** Push null */
ACONST_NULL(Classfile.ACONST_NULL, 1, Kind.CONSTANT, TypeKind.ReferenceType, 0, ConstantDescs.NULL),
+
+ /** Push int constant -1 */
ICONST_M1(Classfile.ICONST_M1, 1, Kind.CONSTANT, TypeKind.IntType, 0, -1),
+
+ /** Push int constant 0 */
ICONST_0(Classfile.ICONST_0, 1, Kind.CONSTANT, TypeKind.IntType, 0, 0),
+
+ /** Push int constant 1 */
ICONST_1(Classfile.ICONST_1, 1, Kind.CONSTANT, TypeKind.IntType, 0, 1),
+
+ /** Push int constant 2 */
ICONST_2(Classfile.ICONST_2, 1, Kind.CONSTANT, TypeKind.IntType, 0, 2),
+
+ /** Push int constant 3 */
ICONST_3(Classfile.ICONST_3, 1, Kind.CONSTANT, TypeKind.IntType, 0, 3),
+
+ /** Push int constant 4 */
ICONST_4(Classfile.ICONST_4, 1, Kind.CONSTANT, TypeKind.IntType, 0, 4),
+
+ /** Push int constant 5 */
ICONST_5(Classfile.ICONST_5, 1, Kind.CONSTANT, TypeKind.IntType, 0, 5),
+
+ /** Push long constant 0 */
LCONST_0(Classfile.LCONST_0, 1, Kind.CONSTANT, TypeKind.LongType, 0, 0L),
+
+ /** Push long constant 1 */
LCONST_1(Classfile.LCONST_1, 1, Kind.CONSTANT, TypeKind.LongType, 0, 1L),
+
+ /** Push float constant 0 */
FCONST_0(Classfile.FCONST_0, 1, Kind.CONSTANT, TypeKind.FloatType, 0, 0.0f),
+
+ /** Push float constant 1 */
FCONST_1(Classfile.FCONST_1, 1, Kind.CONSTANT, TypeKind.FloatType, 0, 1.0f),
+
+ /** Push float constant 2 */
FCONST_2(Classfile.FCONST_2, 1, Kind.CONSTANT, TypeKind.FloatType, 0, 2.0f),
+
+ /** Push double constant 0 */
DCONST_0(Classfile.DCONST_0, 1, Kind.CONSTANT, TypeKind.DoubleType, 0, 0.0d),
+
+ /** Push double constant 1 */
DCONST_1(Classfile.DCONST_1, 1, Kind.CONSTANT, TypeKind.DoubleType, 0, 1.0d),
+
+ /** Push byte */
BIPUSH(Classfile.BIPUSH, 2, Kind.CONSTANT, TypeKind.ByteType),
+
+ /** Push short */
SIPUSH(Classfile.SIPUSH, 3, Kind.CONSTANT, TypeKind.ShortType),
+
+ /** Push item from run-time constant pool */
LDC(Classfile.LDC, 2, Kind.CONSTANT),
+
+ /** Push item from run-time constant pool (wide index) */
LDC_W(Classfile.LDC_W, 3, Kind.CONSTANT),
+
+ /** Push long or double from run-time constant pool (wide index) */
LDC2_W(Classfile.LDC2_W, 3, Kind.CONSTANT),
+
+ /** Load int from local variable */
ILOAD(Classfile.ILOAD, 2, Kind.LOAD, TypeKind.IntType, -1),
+
+ /** Load long from local variable */
LLOAD(Classfile.LLOAD, 2, Kind.LOAD, TypeKind.LongType, -1),
+
+ /** Load float from local variable */
FLOAD(Classfile.FLOAD, 2, Kind.LOAD, TypeKind.FloatType, -1),
+
+ /** Load double from local variable */
DLOAD(Classfile.DLOAD, 2, Kind.LOAD, TypeKind.DoubleType, -1),
+
+ /** Load reference from local variable */
ALOAD(Classfile.ALOAD, 2, Kind.LOAD, TypeKind.ReferenceType, -1),
+
+ /** Load int from local variable 0 */
ILOAD_0(Classfile.ILOAD_0, 1, Kind.LOAD, TypeKind.IntType, 0),
+
+ /** Load int from local variable 1 */
ILOAD_1(Classfile.ILOAD_1, 1, Kind.LOAD, TypeKind.IntType, 1),
+
+ /** Load int from local variable 2 */
ILOAD_2(Classfile.ILOAD_2, 1, Kind.LOAD, TypeKind.IntType, 2),
+
+ /** Load int from local variable3 */
ILOAD_3(Classfile.ILOAD_3, 1, Kind.LOAD, TypeKind.IntType, 3),
+
+ /** Load long from local variable 0 */
LLOAD_0(Classfile.LLOAD_0, 1, Kind.LOAD, TypeKind.LongType, 0),
+
+ /** Load long from local variable 1 */
LLOAD_1(Classfile.LLOAD_1, 1, Kind.LOAD, TypeKind.LongType, 1),
+
+ /** Load long from local variable 2 */
LLOAD_2(Classfile.LLOAD_2, 1, Kind.LOAD, TypeKind.LongType, 2),
+
+ /** Load long from local variable 3 */
LLOAD_3(Classfile.LLOAD_3, 1, Kind.LOAD, TypeKind.LongType, 3),
+
+ /** Load float from local variable 0 */
FLOAD_0(Classfile.FLOAD_0, 1, Kind.LOAD, TypeKind.FloatType, 0),
+
+ /** Load float from local variable 1 */
FLOAD_1(Classfile.FLOAD_1, 1, Kind.LOAD, TypeKind.FloatType, 1),
+
+ /** Load float from local variable 2 */
FLOAD_2(Classfile.FLOAD_2, 1, Kind.LOAD, TypeKind.FloatType, 2),
+
+ /** Load float from local variable 3 */
FLOAD_3(Classfile.FLOAD_3, 1, Kind.LOAD, TypeKind.FloatType, 3),
+
+ /** Load double from local variable 0 */
DLOAD_0(Classfile.DLOAD_0, 1, Kind.LOAD, TypeKind.DoubleType, 0),
+
+ /** Load double from local variable 1 */
DLOAD_1(Classfile.DLOAD_1, 1, Kind.LOAD, TypeKind.DoubleType, 1),
+
+ /** Load double from local variable 2 */
DLOAD_2(Classfile.DLOAD_2, 1, Kind.LOAD, TypeKind.DoubleType, 2),
+
+ /** Load double from local variable 3 */
DLOAD_3(Classfile.DLOAD_3, 1, Kind.LOAD, TypeKind.DoubleType, 3),
+
+ /** Load reference from local variable 0 */
ALOAD_0(Classfile.ALOAD_0, 1, Kind.LOAD, TypeKind.ReferenceType, 0),
+
+ /** Load reference from local variable 1 */
ALOAD_1(Classfile.ALOAD_1, 1, Kind.LOAD, TypeKind.ReferenceType, 1),
+
+ /** Load reference from local variable 2 */
ALOAD_2(Classfile.ALOAD_2, 1, Kind.LOAD, TypeKind.ReferenceType, 2),
+
+ /** Load reference from local variable 3 */
ALOAD_3(Classfile.ALOAD_3, 1, Kind.LOAD, TypeKind.ReferenceType, 3),
+
+ /** Load int from array */
IALOAD(Classfile.IALOAD, 1, Kind.ARRAY_LOAD, TypeKind.IntType),
+
+ /** Load long from array */
LALOAD(Classfile.LALOAD, 1, Kind.ARRAY_LOAD, TypeKind.LongType),
+
+ /** Load float from array */
FALOAD(Classfile.FALOAD, 1, Kind.ARRAY_LOAD, TypeKind.FloatType),
+
+ /** Load double from array */
DALOAD(Classfile.DALOAD, 1, Kind.ARRAY_LOAD, TypeKind.DoubleType),
+
+ /** Load reference from array */
AALOAD(Classfile.AALOAD, 1, Kind.ARRAY_LOAD, TypeKind.ReferenceType),
+
+ /** Load byte from array */
BALOAD(Classfile.BALOAD, 1, Kind.ARRAY_LOAD, TypeKind.ByteType),
+
+ /** Load char from array */
CALOAD(Classfile.CALOAD, 1, Kind.ARRAY_LOAD, TypeKind.CharType),
+
+ /** Load short from array */
SALOAD(Classfile.SALOAD, 1, Kind.ARRAY_LOAD, TypeKind.ShortType),
+
+ /** Store int into local variable */
ISTORE(Classfile.ISTORE, 2, Kind.STORE, TypeKind.IntType, -1),
+
+ /** Store long into local variable */
LSTORE(Classfile.LSTORE, 2, Kind.STORE, TypeKind.LongType, -1),
+
+ /** Store float into local variable */
FSTORE(Classfile.FSTORE, 2, Kind.STORE, TypeKind.FloatType, -1),
+
+ /** Store double into local variable */
DSTORE(Classfile.DSTORE, 2, Kind.STORE, TypeKind.DoubleType, -1),
+
+ /** Store reference into local variable */
ASTORE(Classfile.ASTORE, 2, Kind.STORE, TypeKind.ReferenceType, -1),
+
+ /** Store int into local variable 0 */
ISTORE_0(Classfile.ISTORE_0, 1, Kind.STORE, TypeKind.IntType, 0),
+
+ /** Store int into local variable 1 */
ISTORE_1(Classfile.ISTORE_1, 1, Kind.STORE, TypeKind.IntType, 1),
+
+ /** Store int into local variable 2 */
ISTORE_2(Classfile.ISTORE_2, 1, Kind.STORE, TypeKind.IntType, 2),
+
+ /** Store int into local variable 3 */
ISTORE_3(Classfile.ISTORE_3, 1, Kind.STORE, TypeKind.IntType, 3),
+
+ /** Store long into local variable 0 */
LSTORE_0(Classfile.LSTORE_0, 1, Kind.STORE, TypeKind.LongType, 0),
+
+ /** Store long into local variable 1 */
LSTORE_1(Classfile.LSTORE_1, 1, Kind.STORE, TypeKind.LongType, 1),
+
+ /** Store long into local variable 2 */
LSTORE_2(Classfile.LSTORE_2, 1, Kind.STORE, TypeKind.LongType, 2),
+
+ /** Store long into local variable 3 */
LSTORE_3(Classfile.LSTORE_3, 1, Kind.STORE, TypeKind.LongType, 3),
+
+ /** Store float into local variable 0 */
FSTORE_0(Classfile.FSTORE_0, 1, Kind.STORE, TypeKind.FloatType, 0),
+
+ /** Store float into local variable 1 */
FSTORE_1(Classfile.FSTORE_1, 1, Kind.STORE, TypeKind.FloatType, 1),
+
+ /** Store float into local variable 2 */
FSTORE_2(Classfile.FSTORE_2, 1, Kind.STORE, TypeKind.FloatType, 2),
+
+ /** Store float into local variable 3 */
FSTORE_3(Classfile.FSTORE_3, 1, Kind.STORE, TypeKind.FloatType, 3),
+
+ /** Store double into local variable 0 */
DSTORE_0(Classfile.DSTORE_0, 1, Kind.STORE, TypeKind.DoubleType, 0),
+
+ /** Store double into local variable 1 */
DSTORE_1(Classfile.DSTORE_1, 1, Kind.STORE, TypeKind.DoubleType, 1),
+
+ /** Store double into local variable 2 */
DSTORE_2(Classfile.DSTORE_2, 1, Kind.STORE, TypeKind.DoubleType, 2),
+
+ /** Store double into local variable 3 */
DSTORE_3(Classfile.DSTORE_3, 1, Kind.STORE, TypeKind.DoubleType, 3),
+
+ /** Store reference into local variable 0 */
ASTORE_0(Classfile.ASTORE_0, 1, Kind.STORE, TypeKind.ReferenceType, 0),
+
+ /** Store reference into local variable 1 */
ASTORE_1(Classfile.ASTORE_1, 1, Kind.STORE, TypeKind.ReferenceType, 1),
+
+ /** Store reference into local variable 2 */
ASTORE_2(Classfile.ASTORE_2, 1, Kind.STORE, TypeKind.ReferenceType, 2),
+
+ /** Store reference into local variable 3 */
ASTORE_3(Classfile.ASTORE_3, 1, Kind.STORE, TypeKind.ReferenceType, 3),
+
+ /** Store into int array */
IASTORE(Classfile.IASTORE, 1, Kind.ARRAY_STORE, TypeKind.IntType),
+
+ /** Store into long array */
LASTORE(Classfile.LASTORE, 1, Kind.ARRAY_STORE, TypeKind.LongType),
+
+ /** Store into float array */
FASTORE(Classfile.FASTORE, 1, Kind.ARRAY_STORE, TypeKind.FloatType),
+
+ /** Store into double array */
DASTORE(Classfile.DASTORE, 1, Kind.ARRAY_STORE, TypeKind.DoubleType),
+
+ /** Store into reference array */
AASTORE(Classfile.AASTORE, 1, Kind.ARRAY_STORE, TypeKind.ReferenceType),
+
+ /** Store into byte array */
BASTORE(Classfile.BASTORE, 1, Kind.ARRAY_STORE, TypeKind.ByteType),
+
+ /** Store into char array */
CASTORE(Classfile.CASTORE, 1, Kind.ARRAY_STORE, TypeKind.CharType),
+
+ /** Store into short array */
SASTORE(Classfile.SASTORE, 1, Kind.ARRAY_STORE, TypeKind.ShortType),
+
+ /** Pop the top operand stack value */
POP(Classfile.POP, 1, Kind.STACK),
+
+ /** Pop the top one or two operand stack values */
POP2(Classfile.POP2, 1, Kind.STACK),
+
+ /** Duplicate the top operand stack value */
DUP(Classfile.DUP, 1, Kind.STACK),
+
+ /** Duplicate the top operand stack value and insert two values down */
DUP_X1(Classfile.DUP_X1, 1, Kind.STACK),
+
+ /** Duplicate the top operand stack value and insert two or three values down */
DUP_X2(Classfile.DUP_X2, 1, Kind.STACK),
+
+ /** Duplicate the top one or two operand stack values */
DUP2(Classfile.DUP2, 1, Kind.STACK),
+
+ /** Duplicate the top one or two operand stack values and insert two or three values down */
DUP2_X1(Classfile.DUP2_X1, 1, Kind.STACK),
+
+ /** Duplicate the top one or two operand stack values and insert two, three, or four values down */
DUP2_X2(Classfile.DUP2_X2, 1, Kind.STACK),
+
+ /** Swap the top two operand stack values */
SWAP(Classfile.SWAP, 1, Kind.STACK),
+
+ /** Add int */
IADD(Classfile.IADD, 1, Kind.OPERATOR, TypeKind.IntType),
+
+ /** Add long */
LADD(Classfile.LADD, 1, Kind.OPERATOR, TypeKind.LongType),
+
+ /** Add float */
FADD(Classfile.FADD, 1, Kind.OPERATOR, TypeKind.FloatType),
+
+ /** Add double */
DADD(Classfile.DADD, 1, Kind.OPERATOR, TypeKind.DoubleType),
+
+ /** Subtract int */
ISUB(Classfile.ISUB, 1, Kind.OPERATOR, TypeKind.IntType),
+
+ /** Subtract long */
LSUB(Classfile.LSUB, 1, Kind.OPERATOR, TypeKind.LongType),
+
+ /** Subtract float */
FSUB(Classfile.FSUB, 1, Kind.OPERATOR, TypeKind.FloatType),
+
+ /** Subtract double */
DSUB(Classfile.DSUB, 1, Kind.OPERATOR, TypeKind.DoubleType),
+
+ /** Multiply int */
IMUL(Classfile.IMUL, 1, Kind.OPERATOR, TypeKind.IntType),
+
+ /** Multiply long */
LMUL(Classfile.LMUL, 1, Kind.OPERATOR, TypeKind.LongType),
+
+ /** Multiply float */
FMUL(Classfile.FMUL, 1, Kind.OPERATOR, TypeKind.FloatType),
+
+ /** Multiply double */
DMUL(Classfile.DMUL, 1, Kind.OPERATOR, TypeKind.DoubleType),
+
+ /** Divide int */
IDIV(Classfile.IDIV, 1, Kind.OPERATOR, TypeKind.IntType),
+
+ /** Divide long */
LDIV(Classfile.LDIV, 1, Kind.OPERATOR, TypeKind.LongType),
+
+ /** Divide float */
FDIV(Classfile.FDIV, 1, Kind.OPERATOR, TypeKind.FloatType),
+
+ /** Divide double */
DDIV(Classfile.DDIV, 1, Kind.OPERATOR, TypeKind.DoubleType),
+
+ /** Remainder int */
IREM(Classfile.IREM, 1, Kind.OPERATOR, TypeKind.IntType),
+
+ /** Remainder long */
LREM(Classfile.LREM, 1, Kind.OPERATOR, TypeKind.LongType),
+
+ /** Remainder float */
FREM(Classfile.FREM, 1, Kind.OPERATOR, TypeKind.FloatType),
+
+ /** Remainder double */
DREM(Classfile.DREM, 1, Kind.OPERATOR, TypeKind.DoubleType),
+
+ /** Negate int */
INEG(Classfile.INEG, 1, Kind.OPERATOR, TypeKind.IntType),
+
+ /** Negate long */
LNEG(Classfile.LNEG, 1, Kind.OPERATOR, TypeKind.LongType),
+
+ /** Negate float */
FNEG(Classfile.FNEG, 1, Kind.OPERATOR, TypeKind.FloatType),
+
+ /** Negate double */
DNEG(Classfile.DNEG, 1, Kind.OPERATOR, TypeKind.DoubleType),
+
+ /** Shift left int */
ISHL(Classfile.ISHL, 1, Kind.OPERATOR, TypeKind.IntType),
+
+ /** Shift left long */
LSHL(Classfile.LSHL, 1, Kind.OPERATOR, TypeKind.LongType),
+
+ /** Shift right int */
ISHR(Classfile.ISHR, 1, Kind.OPERATOR, TypeKind.IntType),
+
+ /** Shift right long */
LSHR(Classfile.LSHR, 1, Kind.OPERATOR, TypeKind.LongType),
+
+ /** Logical shift right int */
IUSHR(Classfile.IUSHR, 1, Kind.OPERATOR, TypeKind.IntType),
+
+ /** Logical shift right long */
LUSHR(Classfile.LUSHR, 1, Kind.OPERATOR, TypeKind.LongType),
+
+ /** Boolean AND int */
IAND(Classfile.IAND, 1, Kind.OPERATOR, TypeKind.IntType),
+
+ /** Boolean AND long */
LAND(Classfile.LAND, 1, Kind.OPERATOR, TypeKind.LongType),
+
+ /** Boolean OR int */
IOR(Classfile.IOR, 1, Kind.OPERATOR, TypeKind.IntType),
+
+ /** Boolean OR long */
LOR(Classfile.LOR, 1, Kind.OPERATOR, TypeKind.LongType),
+
+ /** Boolean XOR int */
IXOR(Classfile.IXOR, 1, Kind.OPERATOR, TypeKind.IntType),
+
+ /** Boolean XOR long */
LXOR(Classfile.LXOR, 1, Kind.OPERATOR, TypeKind.LongType),
+
+ /** Increment local variable by constant */
IINC(Classfile.IINC, 3, Kind.INCREMENT, TypeKind.IntType, -1),
+
+ /** Convert int to long */
I2L(Classfile.I2L, 1, Kind.CONVERT, TypeKind.IntType, TypeKind.LongType),
+
+ /** Convert int to float */
I2F(Classfile.I2F, 1, Kind.CONVERT, TypeKind.IntType, TypeKind.FloatType),
+
+ /** Convert int to double */
I2D(Classfile.I2D, 1, Kind.CONVERT, TypeKind.IntType, TypeKind.DoubleType),
+
+ /** Convert long to int */
L2I(Classfile.L2I, 1, Kind.CONVERT, TypeKind.LongType, TypeKind.IntType),
+
+ /** Convert long to float */
L2F(Classfile.L2F, 1, Kind.CONVERT, TypeKind.LongType, TypeKind.FloatType),
+
+ /** Convert long to double */
L2D(Classfile.L2D, 1, Kind.CONVERT, TypeKind.LongType, TypeKind.DoubleType),
+
+ /** Convert float to int */
F2I(Classfile.F2I, 1, Kind.CONVERT, TypeKind.FloatType, TypeKind.IntType),
+
+ /** Convert float to long */
F2L(Classfile.F2L, 1, Kind.CONVERT, TypeKind.FloatType, TypeKind.LongType),
+
+ /** Convert float to double */
F2D(Classfile.F2D, 1, Kind.CONVERT, TypeKind.FloatType, TypeKind.DoubleType),
+
+ /** Convert double to int */
D2I(Classfile.D2I, 1, Kind.CONVERT, TypeKind.DoubleType, TypeKind.IntType),
+
+ /** Convert double to long */
D2L(Classfile.D2L, 1, Kind.CONVERT, TypeKind.DoubleType, TypeKind.LongType),
+
+ /** Convert double to float */
D2F(Classfile.D2F, 1, Kind.CONVERT, TypeKind.DoubleType, TypeKind.FloatType),
+
+ /** Convert int to byte */
I2B(Classfile.I2B, 1, Kind.CONVERT, TypeKind.IntType, TypeKind.ByteType),
+
+ /** Convert int to char */
I2C(Classfile.I2C, 1, Kind.CONVERT, TypeKind.IntType, TypeKind.CharType),
+
+ /** Convert int to short */
I2S(Classfile.I2S, 1, Kind.CONVERT, TypeKind.IntType, TypeKind.ShortType),
+
+ /** Compare long */
LCMP(Classfile.LCMP, 1, Kind.OPERATOR, TypeKind.LongType),
+
+ /** Compare float */
FCMPL(Classfile.FCMPL, 1, Kind.OPERATOR, TypeKind.FloatType),
+
+ /** Compare float */
FCMPG(Classfile.FCMPG, 1, Kind.OPERATOR, TypeKind.FloatType),
+
+ /** Compare double */
DCMPL(Classfile.DCMPL, 1, Kind.OPERATOR, TypeKind.DoubleType),
+
+ /** Compare double */
DCMPG(Classfile.DCMPG, 1, Kind.OPERATOR, TypeKind.DoubleType),
+
+ /** Branch if int comparison with zero succeeds */
IFEQ(Classfile.IFEQ, 3, Kind.BRANCH, TypeKind.IntType),
+
+ /** Branch if int comparison with zero succeeds */
IFNE(Classfile.IFNE, 3, Kind.BRANCH, TypeKind.IntType),
+
+ /** Branch if int comparison with zero succeeds */
IFLT(Classfile.IFLT, 3, Kind.BRANCH, TypeKind.IntType),
+
+ /** Branch if int comparison with zero succeeds */
IFGE(Classfile.IFGE, 3, Kind.BRANCH, TypeKind.IntType),
+
+ /** Branch if int comparison with zero succeeds */
IFGT(Classfile.IFGT, 3, Kind.BRANCH, TypeKind.IntType),
+
+ /** Branch if int comparison with zero succeeds */
IFLE(Classfile.IFLE, 3, Kind.BRANCH, TypeKind.IntType),
+
+ /** Branch if int comparison succeeds */
IF_ICMPEQ(Classfile.IF_ICMPEQ, 3, Kind.BRANCH, TypeKind.IntType),
+
+ /** Branch if int comparison succeeds */
IF_ICMPNE(Classfile.IF_ICMPNE, 3, Kind.BRANCH, TypeKind.IntType),
+
+ /** Branch if int comparison succeeds */
IF_ICMPLT(Classfile.IF_ICMPLT, 3, Kind.BRANCH, TypeKind.IntType),
+
+ /** Branch if int comparison succeeds */
IF_ICMPGE(Classfile.IF_ICMPGE, 3, Kind.BRANCH, TypeKind.IntType),
+
+ /** Branch if int comparison succeeds */
IF_ICMPGT(Classfile.IF_ICMPGT, 3, Kind.BRANCH, TypeKind.IntType),
+
+ /** Branch if int comparison succeeds */
IF_ICMPLE(Classfile.IF_ICMPLE, 3, Kind.BRANCH, TypeKind.IntType),
+
+ /** Branch if reference comparison succeeds */
IF_ACMPEQ(Classfile.IF_ACMPEQ, 3, Kind.BRANCH, TypeKind.ReferenceType),
+
+ /** Branch if reference comparison succeeds */
IF_ACMPNE(Classfile.IF_ACMPNE, 3, Kind.BRANCH, TypeKind.ReferenceType),
+
+ /** Branch always */
GOTO(Classfile.GOTO, 3, Kind.BRANCH, TypeKind.VoidType),
+
+ /** Jump subroutine */
JSR(Classfile.JSR, 3, Kind.DISCONTINUED_JSR),
+
+ /** Return from subroutine */
RET(Classfile.RET, 2, Kind.DISCONTINUED_RET),
+
+ /** Access jump table by index and jump */
TABLESWITCH(Classfile.TABLESWITCH, -1, Kind.TABLE_SWITCH),
+
+ /** Access jump table by key match and jump */
LOOKUPSWITCH(Classfile.LOOKUPSWITCH, -1, Kind.LOOKUP_SWITCH),
+
+ /** Return int from method */
IRETURN(Classfile.IRETURN, 1, Kind.RETURN, TypeKind.IntType),
+
+ /** Return long from method */
LRETURN(Classfile.LRETURN, 1, Kind.RETURN, TypeKind.LongType),
+
+ /** Return float from method */
FRETURN(Classfile.FRETURN, 1, Kind.RETURN, TypeKind.FloatType),
+
+ /** Return double from method */
DRETURN(Classfile.DRETURN, 1, Kind.RETURN, TypeKind.DoubleType),
+
+ /** Return reference from method */
ARETURN(Classfile.ARETURN, 1, Kind.RETURN, TypeKind.ReferenceType),
+
+ /** Return void from method */
RETURN(Classfile.RETURN, 1, Kind.RETURN, TypeKind.VoidType),
+
+ /** Get static field from class */
GETSTATIC(Classfile.GETSTATIC, 3, Kind.FIELD_ACCESS),
+
+ /** Set static field in class */
PUTSTATIC(Classfile.PUTSTATIC, 3, Kind.FIELD_ACCESS),
+
+ /** Fetch field from object */
GETFIELD(Classfile.GETFIELD, 3, Kind.FIELD_ACCESS),
+
+ /** Set field in object */
PUTFIELD(Classfile.PUTFIELD, 3, Kind.FIELD_ACCESS),
+
+ /** Invoke instance method; dispatch based on class */
INVOKEVIRTUAL(Classfile.INVOKEVIRTUAL, 3, Kind.INVOKE),
+
+ /**
+ * Invoke instance method; direct invocation of instance initialization
+ * methods and methods of the current class and its supertypes
+ */
INVOKESPECIAL(Classfile.INVOKESPECIAL, 3, Kind.INVOKE),
+
+ /** Invoke a class (static) method */
INVOKESTATIC(Classfile.INVOKESTATIC, 3, Kind.INVOKE),
+
+ /** Invoke interface method */
INVOKEINTERFACE(Classfile.INVOKEINTERFACE, 5, Kind.INVOKE),
+
+ /** Invoke a dynamically-computed call site */
INVOKEDYNAMIC(Classfile.INVOKEDYNAMIC, 5, Kind.INVOKE_DYNAMIC),
+
+ /** Create new object */
NEW(Classfile.NEW, 3, Kind.NEW_OBJECT),
+
+ /** Create new array */
NEWARRAY(Classfile.NEWARRAY, 2, Kind.NEW_PRIMITIVE_ARRAY),
+
+ /** Create new array of reference */
ANEWARRAY(Classfile.ANEWARRAY, 3, Kind.NEW_REF_ARRAY),
+
+ /** Get length of array */
ARRAYLENGTH(Classfile.ARRAYLENGTH, 1, Kind.OPERATOR, TypeKind.IntType),
+
+ /** Throw exception or error */
ATHROW(Classfile.ATHROW, 1, Kind.THROW_EXCEPTION),
+
+ /** Check whether object is of given type */
CHECKCAST(Classfile.CHECKCAST, 3, Kind.TYPE_CHECK),
+
+ /** Determine if object is of given type */
INSTANCEOF(Classfile.INSTANCEOF, 3, Kind.TYPE_CHECK),
+
+ /** Enter monitor for object */
MONITORENTER(Classfile.MONITORENTER, 1, Kind.MONITOR),
+
+ /** Exit monitor for object */
MONITOREXIT(Classfile.MONITOREXIT, 1, Kind.MONITOR),
+
+ /** Create new multidimensional array */
MULTIANEWARRAY(Classfile.MULTIANEWARRAY, 4, Kind.NEW_MULTI_ARRAY),
+
+ /** Branch if reference is null */
IFNULL(Classfile.IFNULL, 3, Kind.BRANCH, TypeKind.ReferenceType),
+
+ /** Branch if reference not null */
IFNONNULL(Classfile.IFNONNULL, 3, Kind.BRANCH, TypeKind.IntType),
+
+ /** Branch always (wide index) */
GOTO_W(Classfile.GOTO_W, 5, Kind.BRANCH, TypeKind.VoidType),
+
+ /** Jump subroutine (wide index) */
JSR_W(Classfile.JSR_W, 5, Kind.DISCONTINUED_JSR),
+
+ /** Load int from local variable (wide index) */
ILOAD_W((Classfile.WIDE << 8) | Classfile.ILOAD, 4, Kind.LOAD, TypeKind.IntType, -1),
+
+ /** Load long from local variable (wide index) */
LLOAD_W((Classfile.WIDE << 8) | Classfile.LLOAD, 4, Kind.LOAD, TypeKind.LongType, -1),
+
+ /** Load float from local variable (wide index) */
FLOAD_W((Classfile.WIDE << 8) | Classfile.FLOAD, 4, Kind.LOAD, TypeKind.FloatType, -1),
+
+ /** Load double from local variable (wide index) */
DLOAD_W((Classfile.WIDE << 8) | Classfile.DLOAD, 4, Kind.LOAD, TypeKind.DoubleType, -1),
+
+ /** Load reference from local variable (wide index) */
ALOAD_W((Classfile.WIDE << 8) | Classfile.ALOAD, 4, Kind.LOAD, TypeKind.ReferenceType, -1),
+
+ /** Store int into local variable (wide index) */
ISTORE_W((Classfile.WIDE << 8) | Classfile.ISTORE, 4, Kind.STORE, TypeKind.IntType, -1),
+
+ /** Store long into local variable (wide index) */
LSTORE_W((Classfile.WIDE << 8) | Classfile.LSTORE, 4, Kind.STORE, TypeKind.LongType, -1),
+
+ /** Store float into local variable (wide index) */
FSTORE_W((Classfile.WIDE << 8) | Classfile.FSTORE, 4, Kind.STORE, TypeKind.FloatType, -1),
+
+ /** Store double into local variable (wide index) */
DSTORE_W((Classfile.WIDE << 8) | Classfile.DSTORE, 4, Kind.STORE, TypeKind.DoubleType, -1),
+
+ /** Store reference into local variable (wide index) */
ASTORE_W((Classfile.WIDE << 8) | Classfile.ASTORE, 4, Kind.STORE, TypeKind.ReferenceType, -1),
+
+ /** Return from subroutine (wide index) */
RET_W((Classfile.WIDE << 8) | Classfile.RET, 4, Kind.DISCONTINUED_RET),
+
+ /** Increment local variable by constant (wide index) */
IINC_W((Classfile.WIDE << 8) | Classfile.IINC, 6, Kind.INCREMENT, TypeKind.IntType, -1);
/**
* Kinds of opcodes.
*/
public static enum Kind {
- LOAD, STORE, INCREMENT, BRANCH, LOOKUP_SWITCH, TABLE_SWITCH, RETURN, THROW_EXCEPTION,
- FIELD_ACCESS, INVOKE, INVOKE_DYNAMIC,
- NEW_OBJECT, NEW_PRIMITIVE_ARRAY, NEW_REF_ARRAY, NEW_MULTI_ARRAY,
- TYPE_CHECK, ARRAY_LOAD, ARRAY_STORE, STACK, CONVERT, OPERATOR, CONSTANT,
- MONITOR, NOP, DISCONTINUED_JSR, DISCONTINUED_RET;
+
+ /**
+ * Load from local variable
+ *
+ * @see Opcode#ILOAD
+ * @see Opcode#LLOAD
+ * @see Opcode#FLOAD
+ * @see Opcode#DLOAD
+ * @see Opcode#ALOAD
+ * @see Opcode#ILOAD_0
+ * @see Opcode#ILOAD_1
+ * @see Opcode#ILOAD_2
+ * @see Opcode#ILOAD_3
+ * @see Opcode#LLOAD_0
+ * @see Opcode#LLOAD_1
+ * @see Opcode#LLOAD_2
+ * @see Opcode#LLOAD_3
+ * @see Opcode#FLOAD_0
+ * @see Opcode#FLOAD_1
+ * @see Opcode#FLOAD_2
+ * @see Opcode#FLOAD_3
+ * @see Opcode#DLOAD_0
+ * @see Opcode#DLOAD_1
+ * @see Opcode#DLOAD_2
+ * @see Opcode#DLOAD_3
+ * @see Opcode#ALOAD_0
+ * @see Opcode#ALOAD_1
+ * @see Opcode#ALOAD_2
+ * @see Opcode#ALOAD_3
+ * @see Opcode#ILOAD_W
+ * @see Opcode#LLOAD_W
+ * @see Opcode#FLOAD_W
+ * @see Opcode#DLOAD_W
+ * @see Opcode#ALOAD_W
+ */
+ LOAD,
+
+ /**
+ * Store into local variable
+ *
+ * @see Opcode#ISTORE
+ * @see Opcode#LSTORE
+ * @see Opcode#FSTORE
+ * @see Opcode#DSTORE
+ * @see Opcode#ASTORE
+ * @see Opcode#ISTORE_0
+ * @see Opcode#ISTORE_1
+ * @see Opcode#ISTORE_2
+ * @see Opcode#ISTORE_3
+ * @see Opcode#LSTORE_0
+ * @see Opcode#LSTORE_1
+ * @see Opcode#LSTORE_2
+ * @see Opcode#LSTORE_3
+ * @see Opcode#FSTORE_0
+ * @see Opcode#FSTORE_1
+ * @see Opcode#FSTORE_2
+ * @see Opcode#FSTORE_3
+ * @see Opcode#DSTORE_0
+ * @see Opcode#DSTORE_1
+ * @see Opcode#DSTORE_2
+ * @see Opcode#DSTORE_3
+ * @see Opcode#ASTORE_0
+ * @see Opcode#ASTORE_1
+ * @see Opcode#ASTORE_2
+ * @see Opcode#ASTORE_3
+ * @see Opcode#ISTORE_W
+ * @see Opcode#LSTORE_W
+ * @see Opcode#FSTORE_W
+ * @see Opcode#DSTORE_W
+ * @see Opcode#ASTORE_W
+ */
+ STORE,
+
+ /**
+ * Increment local variable
+ *
+ * @see Opcode#IINC
+ * @see Opcode#IINC_W
+ */
+ INCREMENT,
+
+ /**
+ * Branch
+ *
+ * @see Opcode#IFEQ
+ * @see Opcode#IFNE
+ * @see Opcode#IFLT
+ * @see Opcode#IFGE
+ * @see Opcode#IFGT
+ * @see Opcode#IFLE
+ * @see Opcode#IF_ICMPEQ
+ * @see Opcode#IF_ICMPNE
+ * @see Opcode#IF_ICMPLT
+ * @see Opcode#IF_ICMPGE
+ * @see Opcode#IF_ICMPGT
+ * @see Opcode#IF_ICMPLE
+ * @see Opcode#IF_ACMPEQ
+ * @see Opcode#IF_ACMPNE
+ * @see Opcode#GOTO
+ * @see Opcode#IFNULL
+ * @see Opcode#IFNONNULL
+ * @see Opcode#GOTO_W
+ */
+ BRANCH,
+
+ /**
+ * Access jump table by key match and jump
+ *
+ * @see Opcode#LOOKUPSWITCH
+ */
+ LOOKUP_SWITCH,
+
+ /**
+ * Access jump table by index and jump
+ *
+ * @see Opcode#TABLESWITCH
+ */
+ TABLE_SWITCH,
+
+ /**
+ * Return from method
+ *
+ * @see Opcode#IRETURN
+ * @see Opcode#LRETURN
+ * @see Opcode#FRETURN
+ * @see Opcode#DRETURN
+ * @see Opcode#ARETURN
+ * @see Opcode#RETURN
+ */
+ RETURN,
+
+ /**
+ * Throw exception or error
+ *
+ * @see Opcode#ATHROW
+ */
+ THROW_EXCEPTION,
+
+ /**
+ * Access field
+ *
+ * @see Opcode#GETSTATIC
+ * @see Opcode#PUTSTATIC
+ * @see Opcode#GETFIELD
+ * @see Opcode#PUTFIELD
+ */
+ FIELD_ACCESS,
+
+ /**
+ * Invoke method or constructor
+ *
+ * @see Opcode#INVOKEVIRTUAL
+ * @see Opcode#INVOKESPECIAL
+ * @see Opcode#INVOKESTATIC
+ * @see Opcode#INVOKEINTERFACE
+ */
+ INVOKE,
+
+ /**
+ * Invoke a dynamically-computed call site
+ *
+ * @see Opcode#INVOKEDYNAMIC
+ */
+ INVOKE_DYNAMIC,
+
+ /**
+ * Create new object
+ *
+ * @see Opcode#NEW
+ */
+ NEW_OBJECT,
+
+ /**
+ * Create new array
+ *
+ * @see Opcode#NEWARRAY
+ */
+ NEW_PRIMITIVE_ARRAY,
+
+ /**
+ * Create new reference array
+ *
+ * @see Opcode#ANEWARRAY
+ */
+ NEW_REF_ARRAY,
+
+ /**
+ * Create new multidimensional array
+ *
+ * @see Opcode#MULTIANEWARRAY
+ */
+ NEW_MULTI_ARRAY,
+
+ /**
+ * Check whether object is of given type
+ *
+ * @see Opcode#CHECKCAST
+ * @see Opcode#INSTANCEOF
+ */
+ TYPE_CHECK,
+
+ /**
+ * Load from array
+ *
+ * @see Opcode#IALOAD
+ * @see Opcode#LALOAD
+ * @see Opcode#FALOAD
+ * @see Opcode#DALOAD
+ * @see Opcode#AALOAD
+ * @see Opcode#BALOAD
+ * @see Opcode#CALOAD
+ * @see Opcode#SALOAD
+ */
+ ARRAY_LOAD,
+
+ /**
+ * Store into array
+ *
+ * @see Opcode#IASTORE
+ * @see Opcode#LASTORE
+ * @see Opcode#FASTORE
+ * @see Opcode#DASTORE
+ * @see Opcode#AASTORE
+ * @see Opcode#BASTORE
+ * @see Opcode#CASTORE
+ * @see Opcode#SASTORE
+ */
+ ARRAY_STORE,
+
+ /**
+ * Stack operations
+ *
+ * @see Opcode#POP
+ * @see Opcode#POP2
+ * @see Opcode#DUP
+ * @see Opcode#DUP_X1
+ * @see Opcode#DUP_X2
+ * @see Opcode#DUP2
+ * @see Opcode#DUP2_X1
+ * @see Opcode#DUP2_X2
+ * @see Opcode#SWAP
+ */
+ STACK,
+
+ /**
+ * Type conversions
+ *
+ * @see Opcode#I2L
+ * @see Opcode#I2F
+ * @see Opcode#I2D
+ * @see Opcode#L2I
+ * @see Opcode#L2F
+ * @see Opcode#L2D
+ * @see Opcode#F2I
+ * @see Opcode#F2L
+ * @see Opcode#F2D
+ * @see Opcode#D2I
+ * @see Opcode#D2L
+ * @see Opcode#D2F
+ * @see Opcode#I2B
+ * @see Opcode#I2C
+ * @see Opcode#I2S
+ */
+ CONVERT,
+
+ /**
+ * Operators
+ *
+ * @see Opcode#IADD
+ * @see Opcode#LADD
+ * @see Opcode#FADD
+ * @see Opcode#DADD
+ * @see Opcode#ISUB
+ * @see Opcode#LSUB
+ * @see Opcode#FSUB
+ * @see Opcode#DSUB
+ * @see Opcode#IMUL
+ * @see Opcode#LMUL
+ * @see Opcode#FMUL
+ * @see Opcode#DMUL
+ * @see Opcode#IDIV
+ * @see Opcode#LDIV
+ * @see Opcode#FDIV
+ * @see Opcode#DDIV
+ * @see Opcode#IREM
+ * @see Opcode#LREM
+ * @see Opcode#FREM
+ * @see Opcode#DREM
+ * @see Opcode#INEG
+ * @see Opcode#LNEG
+ * @see Opcode#FNEG
+ * @see Opcode#DNEG
+ * @see Opcode#ISHL
+ * @see Opcode#LSHL
+ * @see Opcode#ISHR
+ * @see Opcode#LSHR
+ * @see Opcode#IUSHR
+ * @see Opcode#LUSHR
+ * @see Opcode#IAND
+ * @see Opcode#LAND
+ * @see Opcode#IOR
+ * @see Opcode#LOR
+ * @see Opcode#IXOR
+ * @see Opcode#LXOR
+ * @see Opcode#LCMP
+ * @see Opcode#FCMPL
+ * @see Opcode#FCMPG
+ * @see Opcode#DCMPL
+ * @see Opcode#DCMPG
+ * @see Opcode#ARRAYLENGTH
+ */
+ OPERATOR,
+
+ /**
+ * Constants
+ *
+ * @see Opcode#ACONST_NULL
+ * @see Opcode#ICONST_M1
+ * @see Opcode#ICONST_0
+ * @see Opcode#ICONST_1
+ * @see Opcode#ICONST_2
+ * @see Opcode#ICONST_3
+ * @see Opcode#ICONST_4
+ * @see Opcode#ICONST_5
+ * @see Opcode#LCONST_0
+ * @see Opcode#LCONST_1
+ * @see Opcode#FCONST_0
+ * @see Opcode#FCONST_1
+ * @see Opcode#FCONST_2
+ * @see Opcode#DCONST_0
+ * @see Opcode#DCONST_1
+ * @see Opcode#BIPUSH
+ * @see Opcode#SIPUSH
+ * @see Opcode#LDC
+ * @see Opcode#LDC_W
+ * @see Opcode#LDC2_W
+ */
+ CONSTANT,
+
+ /**
+ * Monitor
+ *
+ * @see Opcode#MONITORENTER
+ * @see Opcode#MONITOREXIT
+ */
+ MONITOR,
+
+ /**
+ * Do nothing
+ *
+ * @see Opcode#NOP
+ */
+ NOP,
+
+ /**
+ * Discontinued jump subroutine
+ *
+ * @see Opcode#JSR
+ * @see Opcode#JSR_W
+ */
+ DISCONTINUED_JSR,
+
+ /**
+ * Discontinued return from subroutine
+ *
+ * @see Opcode#RET
+ * @see Opcode#RET_W
+ */
+ DISCONTINUED_RET;
}
private final int bytecode;
@@ -270,11 +1063,11 @@ public enum Opcode {
private final ConstantDesc constantValue;
Opcode(int bytecode, int sizeIfFixed, Kind kind) {
- this(bytecode, sizeIfFixed, kind, null, null, 0, null);
+ this(bytecode, sizeIfFixed, kind, null, null, -1, null);
}
Opcode(int bytecode, int sizeIfFixed, Kind kind, TypeKind typeKind) {
- this(bytecode, sizeIfFixed, kind, typeKind, null, 0, null);
+ this(bytecode, sizeIfFixed, kind, typeKind, null, -1, null);
}
Opcode(int bytecode, int sizeIfFixed, Kind kind, TypeKind typeKind, int slot) {
@@ -305,30 +1098,57 @@ public enum Opcode {
this.constantValue = constantValue;
}
+ /**
+ * {@return bytecode}
+ */
public int bytecode() { return bytecode; }
+ /**
+ * {@return true if the instruction has extended local variable index by additional bytes}
+ */
public boolean isWide() { return bytecode > 255; }
+ /**
+ * {@return size of the instruction if fixed, or -1 otherwise}
+ */
public int sizeIfFixed() { return sizeIfFixed; }
+ /**
+ * {@return instruction kind}
+ */
public Kind kind() { return kind; }
+ /**
+ * {@return primary type kind for instructions operating with at least one type, or null otherwise}
+ */
public TypeKind primaryTypeKind() {
return primaryTypeKind;
}
+ /**
+ * {@return secondary type kind for instructions operating with two types, or null otherwise}
+ */
public TypeKind secondaryTypeKind() {
return secondaryTypeKind;
}
+ /**
+ * {@return local variable slot for instructions operating with local variable, or -1 otherwise}
+ */
public int slot() {
return slot;
}
+ /**
+ * {@return constant value for constant instructions, or null otherwise}
+ */
public ConstantDesc constantValue() {
return constantValue;
}
+ /**
+ * {@return true if the instruction represents an unconditional branch}
+ */
public boolean isUnconditionalBranch() {
return switch (this) {
case GOTO, ATHROW, GOTO_W, LOOKUPSWITCH, TABLESWITCH -> true;
diff --git a/src/java.base/share/classes/jdk/internal/classfile/Signature.java b/src/java.base/share/classes/jdk/internal/classfile/Signature.java
index 9e513ff622b..ae32ad7d84d 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/Signature.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/Signature.java
@@ -176,7 +176,26 @@ public sealed interface Signature {
* an upper bound, or a lower bound
*/
public enum WildcardIndicator {
- DEFAULT, UNBOUNDED, EXTENDS, SUPER;
+
+ /**
+ * default bound wildcard (empty)
+ */
+ DEFAULT,
+
+ /**
+ * unbounded indicator {@code *}
+ */
+ UNBOUNDED,
+
+ /**
+ * upper-bounded indicator {@code +}
+ */
+ EXTENDS,
+
+ /**
+ * lower-bounded indicator {@code -}
+ */
+ SUPER;
}
/** {@return the wildcard indicator} */
diff --git a/src/java.base/share/classes/jdk/internal/classfile/TypeAnnotation.java b/src/java.base/share/classes/jdk/internal/classfile/TypeAnnotation.java
index 3572ea20f09..4b9c1f1bbc4 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/TypeAnnotation.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/TypeAnnotation.java
@@ -59,7 +59,7 @@ import static jdk.internal.classfile.Classfile.TAT_THROWS;
import jdk.internal.classfile.impl.TemporaryConstantPool;
/**
- * Models an annotation on a type use.
+ * Models an annotation on a type use, as defined in {@jvms 4.7.19} and {@jvms 4.7.20}.
*
* @see RuntimeVisibleTypeAnnotationsAttribute
* @see RuntimeInvisibleTypeAnnotationsAttribute
@@ -69,7 +69,7 @@ public sealed interface TypeAnnotation
permits UnboundAttribute.UnboundTypeAnnotation {
/**
- * The kind of target on which the annotation appears.
+ * The kind of target on which the annotation appears, as defined in {@jvms 4.7.20.1}.
*/
public enum TargetType {
/** For annotations on a class type parameter declaration. */
@@ -146,10 +146,16 @@ public sealed interface TypeAnnotation
this.sizeIfFixed = sizeIfFixed;
}
+ /**
+ * {@return the target type value}
+ */
public int targetTypeValue() {
return targetTypeValue;
}
+ /**
+ * {@return the size of the target type if fixed or -1 if variable}
+ */
public int sizeIfFixed() {
return sizeIfFixed;
}
@@ -225,120 +231,269 @@ public sealed interface TypeAnnotation
*/
sealed interface TargetInfo {
+ /**
+ * {@return the type of the target}
+ */
TargetType targetType();
+ /**
+ * {@return the size of the target info}
+ */
default int size() {
return targetType().sizeIfFixed;
}
+ /**
+ * {@return a target for annotations on a class or method type parameter declaration}
+ * @param targetType {@link TargetType#CLASS_TYPE_PARAMETER} or {@link TargetType#METHOD_TYPE_PARAMETER}
+ * @param typeParameterIndex specifies which type parameter declaration is annotated
+ */
static TypeParameterTarget ofTypeParameter(TargetType targetType, int typeParameterIndex) {
return new TargetInfoImpl.TypeParameterTargetImpl(targetType, typeParameterIndex);
}
+ /**
+ * {@return a target for annotations on a class type parameter declaration}
+ * @param typeParameterIndex specifies which type parameter declaration is annotated
+ */
static TypeParameterTarget ofClassTypeParameter(int typeParameterIndex) {
return ofTypeParameter(TargetType.CLASS_TYPE_PARAMETER, typeParameterIndex);
}
+ /**
+ * {@return a target for annotations on a method type parameter declaration}
+ * @param typeParameterIndex specifies which type parameter declaration is annotated
+ */
static TypeParameterTarget ofMethodTypeParameter(int typeParameterIndex) {
return ofTypeParameter(TargetType.METHOD_TYPE_PARAMETER, typeParameterIndex);
}
+ /**
+ * {@return a target for annotations on the type of an "extends" or "implements" clause}
+ * @param supertypeIndex the index into the interfaces array or 65535 to indicate it is the superclass
+ */
static SupertypeTarget ofClassExtends(int supertypeIndex) {
return new TargetInfoImpl.SupertypeTargetImpl(supertypeIndex);
}
+ /**
+ * {@return a target for annotations on the i'th bound of the j'th type parameter declaration of
+ * a generic class, interface, method, or constructor}
+ * @param targetType {@link TargetType#CLASS_TYPE_PARAMETER_BOUND} or {@link TargetType#METHOD_TYPE_PARAMETER_BOUND}
+ * @param typeParameterIndex specifies which type parameter declaration is annotated
+ * @param boundIndex specifies which bound of the type parameter declaration is annotated
+ */
static TypeParameterBoundTarget ofTypeParameterBound(TargetType targetType, int typeParameterIndex, int boundIndex) {
return new TargetInfoImpl.TypeParameterBoundTargetImpl(targetType, typeParameterIndex, boundIndex);
}
+ /**
+ * {@return a target for annotations on the i'th bound of the j'th type parameter declaration of
+ * a generic class, or interface}
+ * @param typeParameterIndex specifies which type parameter declaration is annotated
+ * @param boundIndex specifies which bound of the type parameter declaration is annotated
+ */
static TypeParameterBoundTarget ofClassTypeParameterBound(int typeParameterIndex, int boundIndex) {
return ofTypeParameterBound(TargetType.CLASS_TYPE_PARAMETER_BOUND, typeParameterIndex, boundIndex);
}
+ /**
+ * {@return a target for annotations on the i'th bound of the j'th type parameter declaration of
+ * a generic method, or constructor}
+ * @param typeParameterIndex specifies which type parameter declaration is annotated
+ * @param boundIndex specifies which bound of the type parameter declaration is annotated
+ */
static TypeParameterBoundTarget ofMethodTypeParameterBound(int typeParameterIndex, int boundIndex) {
return ofTypeParameterBound(TargetType.METHOD_TYPE_PARAMETER_BOUND, typeParameterIndex, boundIndex);
}
+ /**
+ * {@return a target for annotations}
+ * @param targetType {@link TargetType#FIELD}, {@link TargetType#METHOD_RETURN} or {@link TargetType#METHOD_RECEIVER}
+ */
static EmptyTarget of(TargetType targetType) {
return new TargetInfoImpl.EmptyTargetImpl(targetType);
}
+ /**
+ * {@return a target for annotations on the type in a field or record declaration}
+ */
static EmptyTarget ofField() {
return of(TargetType.FIELD);
}
+ /**
+ * {@return a target for annotations on the return type of a method or a newly constructed object}
+ */
static EmptyTarget ofMethodReturn() {
return of(TargetType.METHOD_RETURN);
}
+ /**
+ * {@return a target for annotations on the receiver type of a method or constructor}
+ */
static EmptyTarget ofMethodReceiver() {
return of(TargetType.METHOD_RECEIVER);
}
+ /**
+ * {@return a target for annotations on the type in a formal parameter declaration of a method,
+ * constructor, or lambda expression}
+ * @param formalParameterIndex specifies which formal parameter declaration has an annotated type
+ */
static FormalParameterTarget ofMethodFormalParameter(int formalParameterIndex) {
return new TargetInfoImpl.FormalParameterTargetImpl(formalParameterIndex);
}
+ /**
+ * {@return a target for annotations on the i'th type in the throws clause of a method or
+ * constructor declaration}
+ * @param throwsTargetIndex the index into the exception table of the Exceptions attribute of the method
+ */
static ThrowsTarget ofThrows(int throwsTargetIndex) {
return new TargetInfoImpl.ThrowsTargetImpl(throwsTargetIndex);
}
+ /**
+ * {@return a target for annotations on the type in a local variable declaration,
+ * including a variable declared as a resource in a try-with-resources statement}
+ * @param targetType {@link TargetType#LOCAL_VARIABLE} or {@link TargetType#RESOURCE_VARIABLE}
+ * @param table the list of local variable targets
+ */
static LocalVarTarget ofVariable(TargetType targetType, List table) {
return new TargetInfoImpl.LocalVarTargetImpl(targetType, table);
}
+ /**
+ * {@return a target for annotations on the type in a local variable declaration}
+ * @param table the list of local variable targets
+ */
static LocalVarTarget ofLocalVariable(List table) {
return ofVariable(TargetType.LOCAL_VARIABLE, table);
}
+ /**
+ * {@return a target for annotations on the type in a local variable declared
+ * as a resource in a try-with-resources statement}
+ * @param table the list of local variable targets
+ */
static LocalVarTarget ofResourceVariable(List table) {
return ofVariable(TargetType.RESOURCE_VARIABLE, table);
}
+ /**
+ * {@return a target for annotations on the i'th type in an exception parameter declaration}
+ * @param exceptionTableIndex the index into the exception table of the Code attribute
+ */
static CatchTarget ofExceptionParameter(int exceptionTableIndex) {
return new TargetInfoImpl.CatchTargetImpl(exceptionTableIndex);
}
+ /**
+ * {@return a target for annotations on the type in an instanceof expression or a new expression,
+ * or the type before the :: in a method reference expression}
+ * {@param targetType {@link TargetType#INSTANCEOF}, {@link TargetType#NEW},
+ * {@link TargetType#CONSTRUCTOR_REFERENCE},
+ * or {@link TargetType#METHOD_REFERENCE}}
+ * @param target the code label corresponding to the instruction
+ */
static OffsetTarget ofOffset(TargetType targetType, Label target) {
return new TargetInfoImpl.OffsetTargetImpl(targetType, target);
}
+ /**
+ * {@return a target for annotations on the type in an instanceof expression}
+ * @param target the code label corresponding to the instruction
+ */
static OffsetTarget ofInstanceofExpr(Label target) {
return ofOffset(TargetType.INSTANCEOF, target);
}
+ /**
+ * {@return a target for annotations on the type in a new expression}
+ * @param target the code label corresponding to the instruction
+ */
static OffsetTarget ofNewExpr(Label target) {
return ofOffset(TargetType.NEW, target);
}
+ /**
+ * {@return a target for annotations on the type before the :: in a constructor reference expression}
+ * @param target the code label corresponding to the instruction
+ */
static OffsetTarget ofConstructorReference(Label target) {
return ofOffset(TargetType.CONSTRUCTOR_REFERENCE, target);
}
+ /**
+ * {@return a target for annotations on the type before the :: in a method reference expression}
+ * @param target the code label corresponding to the instruction
+ */
static OffsetTarget ofMethodReference(Label target) {
return ofOffset(TargetType.METHOD_REFERENCE, target);
}
+ /**
+ * {@return a target for annotations on the i'th type in a cast expression,
+ * or on the i'th type argument in the explicit type argument list for any of the following:
+ * a new expression, an explicit constructor invocation statement, a method invocation expression,
+ * or a method reference expression}
+ * {@param targetType {@link TargetType#CAST}, {@link TargetType#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
+ * {@link TargetType#METHOD_INVOCATION_TYPE_ARGUMENT},
+ * {@link TargetType#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT},
+ * or {@link TargetType#METHOD_REFERENCE_TYPE_ARGUMENT}}
+ * @param target the code label corresponding to the instruction
+ * @param typeArgumentIndex specifies which type in the cast operator or argument is annotated
+ */
static TypeArgumentTarget ofTypeArgument(TargetType targetType, Label target, int typeArgumentIndex) {
return new TargetInfoImpl.TypeArgumentTargetImpl(targetType, target, typeArgumentIndex);
}
+ /**
+ * {@return a target for annotations on the i'th type in a cast expression}
+ * @param target the code label corresponding to the instruction
+ * @param typeArgumentIndex specifies which type in the cast operator is annotated
+ */
static TypeArgumentTarget ofCastExpr(Label target, int typeArgumentIndex) {
return ofTypeArgument(TargetType.CAST, target, typeArgumentIndex);
}
+ /**
+ * {@return a target for annotations on the i'th type argument in the explicit type argument list for
+ * an explicit constructor invocation statement}
+ * @param target the code label corresponding to the instruction
+ * @param typeArgumentIndex specifies which type in the argument is annotated
+ */
static TypeArgumentTarget ofConstructorInvocationTypeArgument(Label target, int typeArgumentIndex) {
return ofTypeArgument(TargetType.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT, target, typeArgumentIndex);
}
+ /**
+ * {@return a target for annotations on the i'th type argument in the explicit type argument list for
+ * a method invocation expression}
+ * @param target the code label corresponding to the instruction
+ * @param typeArgumentIndex specifies which type in the argument is annotated
+ */
static TypeArgumentTarget ofMethodInvocationTypeArgument(Label target, int typeArgumentIndex) {
return ofTypeArgument(TargetType.METHOD_INVOCATION_TYPE_ARGUMENT, target, typeArgumentIndex);
}
+ /**
+ * {@return a target for annotations on the i'th type argument in the explicit type argument list for
+ * a new expression}
+ * @param target the code label corresponding to the instruction
+ * @param typeArgumentIndex specifies which type in the argument is annotated
+ */
static TypeArgumentTarget ofConstructorReferenceTypeArgument(Label target, int typeArgumentIndex) {
return ofTypeArgument(TargetType.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT, target, typeArgumentIndex);
}
+ /**
+ * {@return a target for annotations on the i'th type argument in the explicit type argument list for
+ * a method reference expression}
+ * @param target the code label corresponding to the instruction
+ * @param typeArgumentIndex specifies which type in the argument is annotated
+ */
static TypeArgumentTarget ofMethodReferenceTypeArgument(Label target, int typeArgumentIndex) {
return ofTypeArgument(TargetType.METHOD_REFERENCE_TYPE_ARGUMENT, target, typeArgumentIndex);
}
@@ -441,7 +596,7 @@ public sealed interface TypeAnnotation
* Exceptions attribute of the method_info structure enclosing the
* RuntimeVisibleTypeAnnotations attribute.
*
- * @return index into the list jdk.internal.classfile.attribute.ExceptionsAttribute.exceptions()
+ * @return the index into the list jdk.internal.classfile.attribute.ExceptionsAttribute.exceptions()
*/
int throwsTargetIndex();
}
@@ -471,7 +626,7 @@ public sealed interface TypeAnnotation
* The given local variable has a value at indices into the code array in the interval
* [start_pc, start_pc + length), that is, between start_pc inclusive and start_pc + length exclusive.
*
- * @return the start of the bytecode section.
+ * @return the start of the bytecode section
*/
Label startLabel();
@@ -480,7 +635,7 @@ public sealed interface TypeAnnotation
* The given local variable has a value at indices into the code array in the interval
* [start_pc, start_pc + length), that is, between start_pc inclusive and start_pc + length exclusive.
*
- * @return
+ * @return the end of the bytecode section
*/
Label endLabel();
@@ -489,10 +644,16 @@ public sealed interface TypeAnnotation
*
* If the local variable at index is of type double or long, it occupies both index and index + 1.
*
- * @return index into the local variables
+ * @return the index into the local variables
*/
int index();
+ /**
+ * {@return local variable target info}
+ * @param startLabel the code label indicating start of an interval where variable has value
+ * @param endLabel the code label indicating start of an interval where variable has value
+ * @param index index into the local variables
+ */
static LocalVarTargetInfo of(Label startLabel, Label endLabel, int index) {
return new TargetInfoImpl.LocalVarTargetInfoImpl(startLabel, endLabel, index);
}
@@ -526,7 +687,7 @@ public sealed interface TypeAnnotation
* corresponding to the instanceof expression, the new bytecode instruction corresponding to the new
* expression, or the bytecode instruction corresponding to the method reference expression.
*
- * @return
+ * @return the code label corresponding to the instruction
*/
Label target();
}
@@ -547,7 +708,7 @@ public sealed interface TypeAnnotation
* instruction corresponding to the method invocation expression, or the bytecode instruction corresponding to
* the method reference expression.
*
- * @return
+ * @return the code label corresponding to the instruction
*/
Label target();
@@ -567,31 +728,27 @@ public sealed interface TypeAnnotation
}
/**
- * JVMS: Wherever a type is used in a declaration or expression, the type_path structure identifies which part of
- * the type is annotated. An annotation may appear on the type itself, but if the type is a reference type, then
- * there are additional locations where an annotation may appear:
- *
- * If an array type T[] is used in a declaration or expression, then an annotation may appear on any component type
- * of the array type, including the element type.
- *
- * If a nested type T1.T2 is used in a declaration or expression, then an annotation may appear on the name of the
- * innermost member type and any enclosing type for which a type annotation is admissible {@jls 9.7.4}.
- *
- * If a parameterized type {@literal T or T extends A> or T super A>} is used in a declaration or expression, then an
- * annotation may appear on any type argument or on the bound of any wildcard type argument.
- *
- * JVMS: ... each entry in the path array represents an iterative, left-to-right step towards the precise location
- * of the annotation in an array type, nested type, or parameterized type. (In an array type, the iteration visits
- * the array type itself, then its component type, then the component type of that component type, and so on,
- * until the element type is reached.)
+ * JVMS: Type_path structure identifies which part of the type is annotated,
+ * as defined in {@jvms 4.7.20.2}
*/
sealed interface TypePathComponent
permits UnboundAttribute.TypePathComponentImpl {
+ /**
+ * Type path kind, as defined in {@jvms 4.7.20.2}
+ */
public enum Kind {
+
+ /** Annotation is deeper in an array type */
ARRAY(0),
+
+ /** Annotation is deeper in a nested type */
INNER_TYPE(1),
+
+ /** Annotation is on the bound of a wildcard type argument of a parameterized type */
WILDCARD(2),
+
+ /** Annotation is on a type argument of a parameterized type */
TYPE_ARGUMENT(3);
private final int tag;
@@ -600,13 +757,21 @@ public sealed interface TypeAnnotation
this.tag = tag;
}
+ /**
+ * {@return the type path kind value}
+ */
public int tag() {
return tag;
}
}
+ /** static instance for annotation is deeper in an array type */
TypePathComponent ARRAY = new UnboundAttribute.TypePathComponentImpl(Kind.ARRAY, 0);
+
+ /** static instance for annotation is deeper in a nested type */
TypePathComponent INNER_TYPE = new UnboundAttribute.TypePathComponentImpl(Kind.INNER_TYPE, 0);
+
+ /** static instance for annotation is on the bound of a wildcard type argument of a parameterized type */
TypePathComponent WILDCARD = new UnboundAttribute.TypePathComponentImpl(Kind.WILDCARD, 0);
@@ -629,6 +794,11 @@ public sealed interface TypeAnnotation
*/
int typeArgumentIndex();
+ /**
+ * {@return type path component of an annotation}
+ * @param typePathKind the kind of path element
+ * @param typeArgumentIndex the type argument index
+ */
static TypePathComponent of(Kind typePathKind, int typeArgumentIndex) {
return switch (typePathKind) {
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/AnnotationDefaultAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/AnnotationDefaultAttribute.java
index 790b1370cdc..3a0842cc5f6 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/AnnotationDefaultAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/AnnotationDefaultAttribute.java
@@ -37,6 +37,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* appear on methods of annotation types, and records the default value
* {@jls 9.6.2} for the element corresponding to this method. Delivered as a
* {@link MethodElement} when traversing the elements of a {@link MethodModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface AnnotationDefaultAttribute
extends Attribute, MethodElement
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/BootstrapMethodsAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/BootstrapMethodsAttribute.java
index 69db048af6c..638043f0e09 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/BootstrapMethodsAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/BootstrapMethodsAttribute.java
@@ -37,6 +37,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* Models the {@code BootstrapMethods} attribute {@jvms 4.7.23}, which serves as
* an extension to the constant pool of a classfile. Elements of the bootstrap
* method table are accessed through {@link ConstantPool}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface BootstrapMethodsAttribute
extends Attribute
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/CharacterRangeTableAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/CharacterRangeTableAttribute.java
index 549a4830789..287ecb55fc3 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/CharacterRangeTableAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/CharacterRangeTableAttribute.java
@@ -54,6 +54,8 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* several code index ranges, but there will be a smallest code index range, and
* for each kind of range in which it is enclosed there will be a smallest code
* index range. The character range entries may appear in any order.
+ *
+ * The attribute permits multiple instances in a given location.
*/
public sealed interface CharacterRangeTableAttribute
extends Attribute
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/CodeAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/CodeAttribute.java
index 47f2627cd09..50a2990d949 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/CodeAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/CodeAttribute.java
@@ -35,6 +35,10 @@ import jdk.internal.classfile.impl.BoundAttribute;
* non-abstract methods and contains the bytecode of the method body. Delivered
* as a {@link jdk.internal.classfile.MethodElement} when traversing the elements of a
* {@link jdk.internal.classfile.MethodModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface CodeAttribute extends Attribute, CodeModel
permits BoundAttribute.BoundCodeAttribute {
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/CompilationIDAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/CompilationIDAttribute.java
index 0e536f374fe..588f1fc55d6 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/CompilationIDAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/CompilationIDAttribute.java
@@ -37,6 +37,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* appear on classes and records the compilation time of the class. Delivered
* as a {@link jdk.internal.classfile.ClassElement} when traversing the elements of
* a {@link jdk.internal.classfile.ClassModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface CompilationIDAttribute
extends Attribute, ClassElement
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ConstantValueAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ConstantValueAttribute.java
index a0fecb03dba..17eb6260e62 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ConstantValueAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ConstantValueAttribute.java
@@ -37,6 +37,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* fields and indicates that the field's value is a constant. Delivered as a
* {@link jdk.internal.classfile.FieldElement} when traversing the elements of a
* {@link jdk.internal.classfile.FieldModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface ConstantValueAttribute
extends Attribute, FieldElement
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/DeprecatedAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/DeprecatedAttribute.java
index 0c4272599e8..a55b38a6ae0 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/DeprecatedAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/DeprecatedAttribute.java
@@ -36,6 +36,8 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* classes, methods, and fields. Delivered as a {@link ClassElement},
* {@link MethodElement}, or {@link FieldElement} when traversing the elements
* of a corresponding model.
+ *
+ * The attribute permits multiple instances in a given location.
*/
public sealed interface DeprecatedAttribute
extends Attribute,
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/EnclosingMethodAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/EnclosingMethodAttribute.java
index 505c2f2b590..06c3af0f1b7 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/EnclosingMethodAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/EnclosingMethodAttribute.java
@@ -43,6 +43,10 @@ import jdk.internal.classfile.impl.Util;
* on classes, and indicates that the class is a local or anonymous class.
* Delivered as a {@link ClassElement} when traversing the elements of a {@link
* jdk.internal.classfile.ClassModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface EnclosingMethodAttribute
extends Attribute, ClassElement
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ExceptionsAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ExceptionsAttribute.java
index bcf9f41c5ed..90db3988cbb 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ExceptionsAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ExceptionsAttribute.java
@@ -40,6 +40,10 @@ import jdk.internal.classfile.impl.Util;
* methods, and records the exceptions declared to be thrown by this method.
* Delivered as a {@link MethodElement} when traversing the elements of a
* {@link jdk.internal.classfile.MethodModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface ExceptionsAttribute
extends Attribute, MethodElement
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/InnerClassesAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/InnerClassesAttribute.java
index 89c55ecc456..b92b323bd4e 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/InnerClassesAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/InnerClassesAttribute.java
@@ -37,6 +37,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* appear on classes, and records which classes referenced by this classfile
* are inner classes. Delivered as a {@link jdk.internal.classfile.ClassElement} when
* traversing the elements of a {@link jdk.internal.classfile.ClassModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface InnerClassesAttribute
extends Attribute, ClassElement
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/LineNumberTableAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/LineNumberTableAttribute.java
index 9314dedc6c8..224b0505911 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/LineNumberTableAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/LineNumberTableAttribute.java
@@ -37,6 +37,8 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* Delivered as a {@link jdk.internal.classfile.instruction.LineNumber} when traversing the
* elements of a {@link jdk.internal.classfile.CodeModel}, according to the setting of the
* {@link jdk.internal.classfile.Classfile.LineNumbersOption} option.
+ *
+ * The attribute permits multiple instances in a given location.
*/
public sealed interface LineNumberTableAttribute
extends Attribute
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/LocalVariableTableAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/LocalVariableTableAttribute.java
index e2cd49e8e59..3b409bf7e3c 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/LocalVariableTableAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/LocalVariableTableAttribute.java
@@ -37,6 +37,8 @@ import java.util.List;
* Delivered as a {@link jdk.internal.classfile.instruction.LocalVariable} when traversing the
* elements of a {@link jdk.internal.classfile.CodeModel}, according to the setting of the
* {@link jdk.internal.classfile.Classfile.DebugElementsOption} option.
+ *
+ * The attribute permits multiple instances in a given location.
*/
public sealed interface LocalVariableTableAttribute
extends Attribute
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/LocalVariableTypeTableAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/LocalVariableTypeTableAttribute.java
index cbe1257ad54..a0016cd2e23 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/LocalVariableTypeTableAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/LocalVariableTypeTableAttribute.java
@@ -38,6 +38,8 @@ import java.util.List;
* Delivered as a {@link jdk.internal.classfile.instruction.LocalVariable} when traversing the
* elements of a {@link jdk.internal.classfile.CodeModel}, according to the setting of the
* {@link jdk.internal.classfile.Classfile.LineNumbersOption} option.
+ *
+ * The attribute permits multiple instances in a given location.
*/
public sealed interface LocalVariableTypeTableAttribute
extends Attribute
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/MethodParametersAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/MethodParametersAttribute.java
index a3486db891d..8f9b14ffe04 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/MethodParametersAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/MethodParametersAttribute.java
@@ -37,6 +37,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* appear on methods, and records optional information about the method's
* parameters. Delivered as a {@link jdk.internal.classfile.MethodElement} when
* traversing the elements of a {@link jdk.internal.classfile.MethodModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface MethodParametersAttribute
extends Attribute, MethodElement
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleAttribute.java
index bc684d8632a..9be842a04dd 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleAttribute.java
@@ -49,6 +49,10 @@ import jdk.internal.classfile.impl.Util;
* appear on classes that represent module descriptors.
* Delivered as a {@link jdk.internal.classfile.ClassElement} when
* traversing the elements of a {@link jdk.internal.classfile.ClassModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface ModuleAttribute
@@ -72,12 +76,17 @@ public sealed interface ModuleAttribute
return AccessFlag.maskToAccessFlags(moduleFlagsMask(), AccessFlag.Location.MODULE);
}
+ /**
+ * Tests presence of module flag
+ * @param flag the module flag
+ * @return true if the flag is set
+ */
default boolean has(AccessFlag flag) {
return Util.has(AccessFlag.Location.MODULE, moduleFlagsMask(), flag);
}
/**
- * {@return version of the module, if present}
+ * {@return the version of the module, if present}
*/
Optional moduleVersion();
@@ -155,40 +164,156 @@ public sealed interface ModuleAttribute
return mb.build();
}
+ /**
+ * A builder for module attributes.
+ */
public sealed interface ModuleAttributeBuilder
permits ModuleAttributeBuilderImpl {
+ /**
+ * Sets the module name
+ * @param moduleName the module name
+ * @return this builder
+ */
ModuleAttributeBuilder moduleName(ModuleDesc moduleName);
+
+ /**
+ * Sets the module flags
+ * @param flagsMask the module flags
+ * @return this builder
+ */
ModuleAttributeBuilder moduleFlags(int flagsMask);
+
+ /**
+ * Sets the module flags
+ * @param moduleFlags the module flags
+ * @return this builder
+ */
default ModuleAttributeBuilder moduleFlags(AccessFlag... moduleFlags) {
return moduleFlags(Util.flagsToBits(AccessFlag.Location.MODULE, moduleFlags));
}
+
+ /**
+ * Sets the module flags
+ * @param version the module version
+ * @return this builder
+ */
ModuleAttributeBuilder moduleVersion(String version);
+ /**
+ * Adds module requirement
+ * @param module the required module
+ * @param requiresFlagsMask the requires flags
+ * @param version the required module version
+ * @return this builder
+ */
ModuleAttributeBuilder requires(ModuleDesc module, int requiresFlagsMask, String version);
+
+ /**
+ * Adds module requirement
+ * @param module the required module
+ * @param requiresFlags the requires flags
+ * @param version the required module version
+ * @return this builder
+ */
default ModuleAttributeBuilder requires(ModuleDesc module, Collection requiresFlags, String version) {
return requires(module, Util.flagsToBits(AccessFlag.Location.MODULE_REQUIRES, requiresFlags), version);
}
+
+ /**
+ * Adds module requirement
+ * @param requires the module require info
+ * @return this builder
+ */
ModuleAttributeBuilder requires(ModuleRequireInfo requires);
+ /**
+ * Adds exported package
+ * @param pkge the exported package
+ * @param exportsFlagsMask the export flags
+ * @param exportsToModules the modules to export to
+ * @return this builder
+ */
ModuleAttributeBuilder exports(PackageDesc pkge, int exportsFlagsMask, ModuleDesc... exportsToModules);
+
+ /**
+ * Adds exported package
+ * @param pkge the exported package
+ * @param exportsFlags the export flags
+ * @param exportsToModules the modules to export to
+ * @return this builder
+ */
default ModuleAttributeBuilder exports(PackageDesc pkge, Collection exportsFlags, ModuleDesc... exportsToModules) {
return exports(pkge, Util.flagsToBits(AccessFlag.Location.MODULE_EXPORTS, exportsFlags), exportsToModules);
}
+
+ /**
+ * Adds exported package
+ * @param exports the module export info
+ * @return this builder
+ */
ModuleAttributeBuilder exports(ModuleExportInfo exports);
+ /**
+ *
+ * @param pkge the opened package
+ * @param opensFlagsMask the open package flags
+ * @param opensToModules the modules to open to
+ * @return this builder
+ */
ModuleAttributeBuilder opens(PackageDesc pkge, int opensFlagsMask, ModuleDesc... opensToModules);
+
+ /**
+ *
+ * @param pkge the opened package
+ * @param opensFlags the open package flags
+ * @param opensToModules the modules to open to
+ * @return this builder
+ */
default ModuleAttributeBuilder opens(PackageDesc pkge, Collection opensFlags, ModuleDesc... opensToModules) {
return opens(pkge, Util.flagsToBits(AccessFlag.Location.MODULE_OPENS, opensFlags), opensToModules);
}
+
+ /**
+ * Opens package
+ * @param opens the module open info
+ * @return this builder
+ */
ModuleAttributeBuilder opens(ModuleOpenInfo opens);
+ /**
+ * Declares use of a service
+ * @param service the service class used
+ * @return this builder
+ */
ModuleAttributeBuilder uses(ClassDesc service);
+
+ /**
+ * Declares use of a service
+ * @param uses the service class used
+ * @return this builder
+ */
ModuleAttributeBuilder uses(ClassEntry uses);
+ /**
+ * Declares provision of a service
+ * @param service the service class provided
+ * @param implClasses the implementation classes
+ * @return this builder
+ */
ModuleAttributeBuilder provides(ClassDesc service, ClassDesc... implClasses);
+
+ /**
+ * Declares provision of a service
+ * @param provides the module provides info
+ * @return this builder
+ */
ModuleAttributeBuilder provides(ModuleProvideInfo provides);
+ /**
+ * Builds module attribute.
+ * @return the module attribute
+ */
ModuleAttribute build();
}
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleHashesAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleHashesAttribute.java
index 5447ea0e043..e1b3af294c3 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleHashesAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleHashesAttribute.java
@@ -63,6 +63,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
*
* }
* }
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface ModuleHashesAttribute
extends Attribute, ClassElement
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleMainClassAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleMainClassAttribute.java
index a21e0f4888b..0b429a6afda 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleMainClassAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleMainClassAttribute.java
@@ -38,6 +38,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* appear on classes that represent module descriptors.
* Delivered as a {@link jdk.internal.classfile.ClassElement} when
* traversing the elements of a {@link jdk.internal.classfile.ClassModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface ModuleMainClassAttribute
extends Attribute, ClassElement
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleOpenInfo.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleOpenInfo.java
index 706f9779cf9..9e22b517c3d 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleOpenInfo.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleOpenInfo.java
@@ -56,6 +56,9 @@ public sealed interface ModuleOpenInfo
*/
int opensFlagsMask();
+ /**
+ * {@return the access flags}
+ */
default Set opensFlags() {
return AccessFlag.maskToAccessFlags(opensFlagsMask(), AccessFlag.Location.MODULE_OPENS);
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModulePackagesAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModulePackagesAttribute.java
index f1851835ef9..b53c77859b5 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModulePackagesAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModulePackagesAttribute.java
@@ -41,6 +41,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* appear on classes that represent module descriptors.
* Delivered as a {@link jdk.internal.classfile.ClassElement} when
* traversing the elements of a {@link jdk.internal.classfile.ClassModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface ModulePackagesAttribute
extends Attribute, ClassElement
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleRequireInfo.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleRequireInfo.java
index 313b4020d55..3e56a953b87 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleRequireInfo.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleRequireInfo.java
@@ -56,6 +56,9 @@ public sealed interface ModuleRequireInfo
*/
int requiresFlagsMask();
+ /**
+ * {@return the access flags}
+ */
default Set requiresFlags() {
return AccessFlag.maskToAccessFlags(requiresFlagsMask(), AccessFlag.Location.MODULE_REQUIRES);
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleResolutionAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleResolutionAttribute.java
index c26ead18f4e..0a67d8f2f3c 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleResolutionAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleResolutionAttribute.java
@@ -56,6 +56,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* 0x0008 (WARN_INCUBATING)
* }
* }
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface ModuleResolutionAttribute
extends Attribute, ClassElement
@@ -72,6 +76,7 @@ public sealed interface ModuleResolutionAttribute
* 0x0002 (WARN_DEPRECATED)
* 0x0004 (WARN_DEPRECATED_FOR_REMOVAL)
* 0x0008 (WARN_INCUBATING)
+ * @return the module resolution flags
*/
int resolutionFlags();
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleTargetAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleTargetAttribute.java
index 36beab9e485..744b0bd298a 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleTargetAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleTargetAttribute.java
@@ -51,6 +51,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* u2 target_platform_index;
* }
* }
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface ModuleTargetAttribute
extends Attribute, ClassElement
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/NestHostAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/NestHostAttribute.java
index e2a311a76f3..e8606593511 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/NestHostAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/NestHostAttribute.java
@@ -38,6 +38,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* appear on classes to indicate that this class is a member of a nest.
* Delivered as a {@link jdk.internal.classfile.ClassElement} when
* traversing the elements of a {@link jdk.internal.classfile.ClassModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface NestHostAttribute extends Attribute, ClassElement
permits BoundAttribute.BoundNestHostAttribute,
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/NestMembersAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/NestMembersAttribute.java
index 00c4a595158..82796e26cd5 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/NestMembersAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/NestMembersAttribute.java
@@ -40,6 +40,10 @@ import jdk.internal.classfile.impl.Util;
* appear on classes to indicate that this class is the host of a nest.
* Delivered as a {@link jdk.internal.classfile.ClassElement} when
* traversing the elements of a {@link jdk.internal.classfile.ClassModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface NestMembersAttribute extends Attribute, ClassElement
permits BoundAttribute.BoundNestMembersAttribute, UnboundAttribute.UnboundNestMembersAttribute {
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/PermittedSubclassesAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/PermittedSubclassesAttribute.java
index affad318bf5..11523dd2417 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/PermittedSubclassesAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/PermittedSubclassesAttribute.java
@@ -40,6 +40,10 @@ import jdk.internal.classfile.impl.Util;
* appear on classes to indicate which classes may extend this class.
* Delivered as a {@link jdk.internal.classfile.ClassElement} when
* traversing the elements of a {@link jdk.internal.classfile.ClassModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface PermittedSubclassesAttribute
extends Attribute, ClassElement
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/RecordAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/RecordAttribute.java
index bede1ac97ac..84b9ac49d8a 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/RecordAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/RecordAttribute.java
@@ -37,6 +37,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* appear on classes to indicate that this class is a record class.
* Delivered as a {@link jdk.internal.classfile.ClassElement} when
* traversing the elements of a {@link jdk.internal.classfile.ClassModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface RecordAttribute extends Attribute, ClassElement
permits BoundAttribute.BoundRecordAttribute, UnboundAttribute.UnboundRecordAttribute {
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java
index 6ffbfdc5d45..ff6c5df2fe6 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java
@@ -36,6 +36,10 @@ import java.util.List;
* can appear on classes, methods, and fields. Delivered as a
* {@link jdk.internal.classfile.ClassElement}, {@link jdk.internal.classfile.FieldElement}, or
* {@link jdk.internal.classfile.MethodElement} when traversing the corresponding model type.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface RuntimeInvisibleAnnotationsAttribute
extends Attribute,
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java
index 5140251611b..ef4e5bf8473 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java
@@ -38,6 +38,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* Models the {@code RuntimeInvisibleParameterAnnotations} attribute
* {@jvms 4.7.19}, which can appear on methods. Delivered as a {@link
* jdk.internal.classfile.MethodElement} when traversing a {@link MethodModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface RuntimeInvisibleParameterAnnotationsAttribute
extends Attribute, MethodElement
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java
index f86c7ca1b39..2db2a6270f0 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java
@@ -42,6 +42,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* {@link jdk.internal.classfile.ClassElement}, {@link jdk.internal.classfile.FieldElement},
* {@link jdk.internal.classfile.MethodElement}, or {@link CodeElement} when traversing
* the corresponding model type.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface RuntimeInvisibleTypeAnnotationsAttribute
extends Attribute,
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java
index 98f92546aa6..54ca6926f8a 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java
@@ -36,6 +36,10 @@ import java.util.List;
* can appear on classes, methods, and fields. Delivered as a
* {@link jdk.internal.classfile.ClassElement}, {@link jdk.internal.classfile.FieldElement}, or
* {@link jdk.internal.classfile.MethodElement} when traversing the corresponding model type.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface RuntimeVisibleAnnotationsAttribute
extends Attribute,
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java
index 91d9234c3a1..32947a831a5 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java
@@ -38,6 +38,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* Models the {@code RuntimeVisibleParameterAnnotations} attribute {@jvms 4.7.18}, which
* can appear on methods. Delivered as a {@link jdk.internal.classfile.MethodElement}
* when traversing a {@link MethodModel}.
+ *
+ * @apiNote The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface RuntimeVisibleParameterAnnotationsAttribute
extends Attribute, MethodElement
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java
index 79ca6e435fc..dbb4d8b06f0 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java
@@ -42,6 +42,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* {@link jdk.internal.classfile.ClassElement}, {@link jdk.internal.classfile.FieldElement},
* {@link jdk.internal.classfile.MethodElement}, or {@link CodeElement} when traversing
* the corresponding model type.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface RuntimeVisibleTypeAnnotationsAttribute
extends Attribute,
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/SignatureAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/SignatureAttribute.java
index af83f3522d3..dfcaa4bae7d 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/SignatureAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/SignatureAttribute.java
@@ -43,6 +43,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* {@link jdk.internal.classfile.ClassElement}, {@link jdk.internal.classfile.FieldElement}, or
* {@link jdk.internal.classfile.MethodElement} when traversing
* the corresponding model type.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface SignatureAttribute
extends Attribute,
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceDebugExtensionAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceDebugExtensionAttribute.java
index e5024094510..1771acf2cc9 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceDebugExtensionAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceDebugExtensionAttribute.java
@@ -31,9 +31,13 @@ import jdk.internal.classfile.impl.BoundAttribute;
import jdk.internal.classfile.impl.UnboundAttribute;
/**
- * Models the {@code SourceDebugExtension} attribute (@@@ need reference).
+ * Models the {@code SourceDebugExtension} attribute.
* Delivered as a {@link jdk.internal.classfile.ClassElement} when traversing the elements of
* a {@link jdk.internal.classfile.ClassModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface SourceDebugExtensionAttribute
extends Attribute, ClassElement
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceFileAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceFileAttribute.java
index 7f9a73a8482..7c93deadbf2 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceFileAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceFileAttribute.java
@@ -37,6 +37,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* Models the {@code SourceFile} attribute {@jvms 4.7.10}, which
* can appear on classes. Delivered as a {@link jdk.internal.classfile.ClassElement}
* when traversing a {@link ClassModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface SourceFileAttribute
extends Attribute, ClassElement
@@ -47,10 +51,18 @@ public sealed interface SourceFileAttribute
*/
Utf8Entry sourceFile();
+ /**
+ * {@return a source file attribute}
+ * @param sourceFile the source file name
+ */
static SourceFileAttribute of(String sourceFile) {
return of(TemporaryConstantPool.INSTANCE.utf8Entry(sourceFile));
}
+ /**
+ * {@return a source file attribute}
+ * @param sourceFile the source file name
+ */
static SourceFileAttribute of(Utf8Entry sourceFile) {
return new UnboundAttribute.UnboundSourceFileAttribute(sourceFile);
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceIDAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceIDAttribute.java
index 05534e434df..22aa9390a26 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceIDAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceIDAttribute.java
@@ -34,9 +34,13 @@ import jdk.internal.classfile.impl.TemporaryConstantPool;
import jdk.internal.classfile.impl.UnboundAttribute;
/**
- * Models the {@code SourceID} attribute (@@@ reference needed), which can
+ * Models the {@code SourceID} attribute, which can
* appear on classes. Delivered as a {@link jdk.internal.classfile.ClassElement} when
* traversing a {@link ClassModel}.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface SourceIDAttribute
extends Attribute, ClassElement
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/StackMapFrameInfo.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/StackMapFrameInfo.java
index 82219dcfee8..6c0f9925b30 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/StackMapFrameInfo.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/StackMapFrameInfo.java
@@ -40,11 +40,32 @@ import static jdk.internal.classfile.Classfile.*;
public sealed interface StackMapFrameInfo
permits StackMapDecoder.StackMapFrameImpl {
+ /**
+ * {@return the frame compact form type}
+ */
int frameType();
+
+ /**
+ * {@return the frame target label}
+ */
Label target();
+
+ /**
+ * {@return the expanded local variable types}
+ */
List locals();
+
+ /**
+ * {@return the expanded stack types}
+ */
List stack();
+ /**
+ * {@return a new stack map frame}
+ * @param target the location of the frame
+ * @param locals the complete list of frame locals
+ * @param stack the complete frame stack
+ */
public static StackMapFrameInfo of(Label target,
List locals,
List stack) {
@@ -56,6 +77,10 @@ public sealed interface StackMapFrameInfo
* The type of a stack value.
*/
sealed interface VerificationTypeInfo {
+
+ /**
+ * {@return the tag of the type info}
+ */
int tag();
}
@@ -63,12 +88,26 @@ public sealed interface StackMapFrameInfo
* A simple stack value.
*/
public enum SimpleVerificationTypeInfo implements VerificationTypeInfo {
+
+ /** verification type top */
ITEM_TOP(VT_TOP),
+
+ /** verification type int */
ITEM_INTEGER(VT_INTEGER),
+
+ /** verification type float */
ITEM_FLOAT(VT_FLOAT),
+
+ /** verification type double */
ITEM_DOUBLE(VT_DOUBLE),
+
+ /** verification type long */
ITEM_LONG(VT_LONG),
+
+ /** verification type null */
ITEM_NULL(VT_NULL),
+
+ /** verification type uninitializedThis */
ITEM_UNINITIALIZED_THIS(VT_UNINITIALIZED_THIS);
@@ -90,19 +129,30 @@ public sealed interface StackMapFrameInfo
sealed interface ObjectVerificationTypeInfo extends VerificationTypeInfo
permits StackMapDecoder.ObjectVerificationTypeInfoImpl {
+ /**
+ * {@return a new object verification type info}
+ * @param className the class of the object
+ */
public static ObjectVerificationTypeInfo of(ClassEntry className) {
return new StackMapDecoder.ObjectVerificationTypeInfoImpl(className);
}
+ /**
+ * {@return a new object verification type info}
+ * @param classDesc the class of the object
+ */
public static ObjectVerificationTypeInfo of(ClassDesc classDesc) {
return of(TemporaryConstantPool.INSTANCE.classEntry(classDesc));
}
/**
- * {@return the class of the value}
+ * {@return the class of the object}
*/
ClassEntry className();
+ /**
+ * {@return the class of the object}
+ */
default ClassDesc classSymbol() {
return className().asSymbol();
}
@@ -113,8 +163,16 @@ public sealed interface StackMapFrameInfo
*/
sealed interface UninitializedVerificationTypeInfo extends VerificationTypeInfo
permits StackMapDecoder.UninitializedVerificationTypeInfoImpl {
+
+ /**
+ * {@return the {@code new} instruction position that creates this unitialized object}
+ */
Label newTarget();
+ /**
+ * {@return an unitialized verification type info}
+ * @param newTarget the {@code new} instruction position that creates this unitialized object
+ */
public static UninitializedVerificationTypeInfo of(Label newTarget) {
return new StackMapDecoder.UninitializedVerificationTypeInfoImpl(newTarget);
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/StackMapTableAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/StackMapTableAttribute.java
index 6f7cc69b978..ca5d1732021 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/StackMapTableAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/StackMapTableAttribute.java
@@ -35,6 +35,10 @@ import jdk.internal.classfile.impl.UnboundAttribute;
/**
* Models the {@code StackMapTable} attribute {@jvms 4.7.4}, which can appear
* on a {@code Code} attribute.
+ *
+ * The attribute does not permit multiple instances in a given location.
+ * Subsequent occurrence of the attribute takes precedence during the attributed
+ * element build or transformation.
*/
public sealed interface StackMapTableAttribute
extends Attribute, CodeElement
@@ -45,6 +49,10 @@ public sealed interface StackMapTableAttribute
*/
List entries();
+ /**
+ * {@return a stack map table attribute}
+ * @param entries the stack map frames
+ */
public static StackMapTableAttribute of(List entries) {
return new UnboundAttribute.UnboundStackMapTableAttribute(entries);
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/SyntheticAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/SyntheticAttribute.java
index 7f84ed496a0..a4aee1408a1 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/attribute/SyntheticAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/SyntheticAttribute.java
@@ -37,6 +37,8 @@ import jdk.internal.classfile.impl.UnboundAttribute;
* classes, methods, and fields. Delivered as a {@link ClassElement},
* {@link MethodElement}, or {@link FieldElement} when traversing the elements
* of a corresponding model.
+ *
+ * The attribute permits multiple instances in a given location.
*/
public sealed interface SyntheticAttribute
extends Attribute,
diff --git a/src/java.base/share/classes/jdk/internal/classfile/instruction/BranchInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/instruction/BranchInstruction.java
index 7ad5c1a649a..4223adf5d9f 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/instruction/BranchInstruction.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/instruction/BranchInstruction.java
@@ -51,6 +51,7 @@ public sealed interface BranchInstruction extends Instruction
*
* @param op the opcode for the specific type of branch instruction,
* which must be of kind {@link Opcode.Kind#BRANCH}
+ * @param target the target of the branch
*/
static BranchInstruction of(Opcode op, Label target) {
Util.checkKind(op, Opcode.Kind.BRANCH);
diff --git a/src/java.base/share/classes/jdk/internal/classfile/instruction/LabelTarget.java b/src/java.base/share/classes/jdk/internal/classfile/instruction/LabelTarget.java
index a6948e07369..029eb37ea5b 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/instruction/LabelTarget.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/instruction/LabelTarget.java
@@ -39,5 +39,9 @@ import jdk.internal.classfile.impl.LabelImpl;
*/
public sealed interface LabelTarget extends PseudoInstruction
permits LabelImpl {
+
+ /**
+ * {@return the label corresponding to this target}
+ */
Label label();
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/instruction/LoadInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/instruction/LoadInstruction.java
index 0d91f285cc1..935e33d64b5 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/instruction/LoadInstruction.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/instruction/LoadInstruction.java
@@ -42,8 +42,15 @@ import jdk.internal.classfile.impl.Util;
public sealed interface LoadInstruction extends Instruction
permits AbstractInstruction.BoundLoadInstruction,
AbstractInstruction.UnboundLoadInstruction {
+
+ /**
+ * {@return the local variable slot to load from}
+ */
int slot();
+ /**
+ * {@return the type of the value to be loaded}
+ */
TypeKind typeKind();
/**
diff --git a/src/java.base/share/classes/jdk/internal/classfile/instruction/LocalVariable.java b/src/java.base/share/classes/jdk/internal/classfile/instruction/LocalVariable.java
index ac803e3cf3c..9fbc991416a 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/instruction/LocalVariable.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/instruction/LocalVariable.java
@@ -80,6 +80,12 @@ public sealed interface LocalVariable extends PseudoInstruction
*/
Label endScope();
+ /**
+ * Writes the local variable to the specified writer
+ *
+ * @param buf the writer
+ * @return true if the variable has been written
+ */
boolean writeTo(BufWriter buf);
/**
diff --git a/src/java.base/share/classes/jdk/internal/classfile/instruction/LocalVariableType.java b/src/java.base/share/classes/jdk/internal/classfile/instruction/LocalVariableType.java
index 3c01f1df3d4..168552a7ee2 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/instruction/LocalVariableType.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/instruction/LocalVariableType.java
@@ -77,6 +77,12 @@ public sealed interface LocalVariableType extends PseudoInstruction
*/
Label endScope();
+ /**
+ * Writes the local variable to the specified writer
+ *
+ * @param buf the writer
+ * @return true if the variable has been written
+ */
boolean writeTo(BufWriter buf);
/**
diff --git a/src/java.base/share/classes/jdk/internal/classfile/instruction/ReturnInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/instruction/ReturnInstruction.java
index ee17d758a97..35afaae898f 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/instruction/ReturnInstruction.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/instruction/ReturnInstruction.java
@@ -41,6 +41,10 @@ import jdk.internal.classfile.impl.Util;
*/
public sealed interface ReturnInstruction extends Instruction
permits AbstractInstruction.UnboundReturnInstruction {
+
+ /**
+ * {@return the type of the return instruction}
+ */
TypeKind typeKind();
/**
diff --git a/src/java.base/share/classes/jdk/internal/classfile/instruction/StoreInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/instruction/StoreInstruction.java
index b7c26ac1b31..a6254dfc052 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/instruction/StoreInstruction.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/instruction/StoreInstruction.java
@@ -41,7 +41,15 @@ import jdk.internal.classfile.impl.Util;
*/
public sealed interface StoreInstruction extends Instruction
permits AbstractInstruction.BoundStoreInstruction, AbstractInstruction.UnboundStoreInstruction {
+
+ /**
+ * {@return the local variable slot to store to}
+ */
int slot();
+
+ /**
+ * {@return the type of the value to be stored}
+ */
TypeKind typeKind();
/**
diff --git a/src/java.base/share/classes/jdk/internal/classfile/instruction/TypeCheckInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/instruction/TypeCheckInstruction.java
index 19400079b3d..a777edb39fd 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/instruction/TypeCheckInstruction.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/instruction/TypeCheckInstruction.java
@@ -43,6 +43,10 @@ import jdk.internal.classfile.impl.Util;
public sealed interface TypeCheckInstruction extends Instruction
permits AbstractInstruction.BoundTypeCheckInstruction,
AbstractInstruction.UnboundTypeCheckInstruction {
+
+ /**
+ * {@return the type against which the instruction checks or casts}
+ */
ClassEntry type();
/**
diff --git a/src/java.base/share/classes/jdk/internal/classfile/package-info.java b/src/java.base/share/classes/jdk/internal/classfile/package-info.java
index 1286f791c61..db14e8f61c9 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/package-info.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/package-info.java
@@ -211,7 +211,12 @@
* builders for the constructor and {@code main} method, and in turn use the
* method builders to create a {@code Code} attribute and use the code builders
* to generate the instructions:
- * {@snippet lang="java" class="PackageSnippets" region="helloWorld"}
+ * {@snippet lang="java" class="PackageSnippets" region="helloWorld1"}
+ *
+ * The convenience methods {@code ClassBuilder.buildMethodBody} allows us to ask
+ * {@link ClassBuilder} to create code builders to build method bodies directly,
+ * skipping the method builder custom lambda:
+ * {@snippet lang="java" class="PackageSnippets" region="helloWorld2"}
*
* Builders often support multiple ways of expressing the same entity at
* different levels of abstraction. For example, the {@code invokevirtual}
@@ -276,9 +281,13 @@
* builder and an element, and an implementation "flatMap"s elements
* into the builder. We could express the above as:
* {@snippet lang="java" class="PackageSnippets" region="stripDebugMethods2"}
+ *
+ * {@code ClassTransform.dropping} convenience method allow us to simplify the same
+ * transformation construction and express the above as:
+ * {@snippet lang="java" class="PackageSnippets" region="stripDebugMethods3"}
*
*
Lifting transforms
- * While the second example is only slightly shorter than the first, the
+ * While the example using transformations are only slightly shorter, the
* advantage of expressing transformation in this way is that the transform
* operations can be more easily combined. Suppose we want to redirect
* invocations of static methods on {@code Foo} to the corresponding method on
@@ -301,6 +310,11 @@
* ClassTransform ct = ClassTransform.transformingMethods(mt);
* }
*
+ * or lift the code transform into the class transform directly:
+ * {@snippet lang=java :
+ * ClassTransform ct = ClassTransform.transformingMethodBodiess(fooToBar);
+ * }
+ *
* and then transform the classfile:
* {@snippet lang=java :
* var cc = Classfile.of();
diff --git a/src/java.base/share/classes/jdk/internal/classfile/snippet-files/PackageSnippets.java b/src/java.base/share/classes/jdk/internal/classfile/snippet-files/PackageSnippets.java
index b22c7dd0548..16c467c77d9 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/snippet-files/PackageSnippets.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/snippet-files/PackageSnippets.java
@@ -132,28 +132,41 @@ class PackageSnippets {
private static final MethodTypeDesc MTD_void_StringArray = MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_String.arrayType());
private static final MethodTypeDesc MTD_void_String = MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_String);
- void writeHelloWorld() {
- // @start region="helloWorld"
- byte[] bytes = Classfile.of().build(CD_Hello, cb -> {
- cb.withFlags(AccessFlag.PUBLIC);
- cb.withMethod(ConstantDescs.INIT_NAME, ConstantDescs.MTD_void, Classfile.ACC_PUBLIC,
- mb -> mb.withCode(
- b -> b.aload(0)
- .invokespecial(ConstantDescs.CD_Object, ConstantDescs.INIT_NAME,
- ConstantDescs.MTD_void)
- .returnInstruction(TypeKind.VoidType)
- )
- )
- .withMethod("main", MTD_void_StringArray,
- Classfile.ACC_PUBLIC,
- mb -> mb.withFlags(AccessFlag.STATIC, AccessFlag.PUBLIC)
- .withCode(
- b -> b.getstatic(CD_System, "out", CD_PrintStream)
- .constantInstruction(Opcode.LDC, "Hello World")
- .invokevirtual(CD_PrintStream, "println", MTD_void_String)
- .returnInstruction(TypeKind.VoidType)
- ));
- });
+ void writeHelloWorld1() {
+ // @start region="helloWorld1"
+ byte[] bytes = Classfile.of().build(CD_Hello,
+ clb -> clb.withFlags(Classfile.ACC_PUBLIC)
+ .withMethod(ConstantDescs.INIT_NAME, ConstantDescs.MTD_void,
+ Classfile.ACC_PUBLIC,
+ mb -> mb.withCode(
+ cob -> cob.aload(0)
+ .invokespecial(ConstantDescs.CD_Object,
+ ConstantDescs.INIT_NAME, ConstantDescs.MTD_void)
+ .return_()))
+ .withMethod("main", MTD_void_StringArray, Classfile.ACC_PUBLIC + Classfile.ACC_STATIC,
+ mb -> mb.withCode(
+ cob -> cob.getstatic(CD_System, "out", CD_PrintStream)
+ .ldc("Hello World")
+ .invokevirtual(CD_PrintStream, "println", MTD_void_String)
+ .return_())));
+ // @end
+ }
+
+ void writeHelloWorld2() {
+ // @start region="helloWorld2"
+ byte[] bytes = Classfile.of().build(CD_Hello,
+ clb -> clb.withFlags(Classfile.ACC_PUBLIC)
+ .withMethodBody(ConstantDescs.INIT_NAME, ConstantDescs.MTD_void,
+ Classfile.ACC_PUBLIC,
+ cob -> cob.aload(0)
+ .invokespecial(ConstantDescs.CD_Object,
+ ConstantDescs.INIT_NAME, ConstantDescs.MTD_void)
+ .return_())
+ .withMethodBody("main", MTD_void_StringArray, Classfile.ACC_PUBLIC + Classfile.ACC_STATIC,
+ cob -> cob.getstatic(CD_System, "out", CD_PrintStream)
+ .ldc("Hello World")
+ .invokevirtual(CD_PrintStream, "println", MTD_void_String)
+ .return_()));
// @end
}
@@ -161,13 +174,14 @@ class PackageSnippets {
// @start region="stripDebugMethods1"
ClassModel classModel = Classfile.of().parse(bytes);
byte[] newBytes = Classfile.of().build(classModel.thisClass().asSymbol(),
- classBuilder -> {
- for (ClassElement ce : classModel) {
- if (!(ce instanceof MethodModel mm
- && mm.methodName().stringValue().startsWith("debug")))
- classBuilder.with(ce);
- }
- });
+ classBuilder -> {
+ for (ClassElement ce : classModel) {
+ if (!(ce instanceof MethodModel mm
+ && mm.methodName().stringValue().startsWith("debug"))) {
+ classBuilder.with(ce);
+ }
+ }
+ });
// @end
}
@@ -182,6 +196,14 @@ class PackageSnippets {
// @end
}
+ void stripDebugMethods3(byte[] bytes) {
+ // @start region="stripDebugMethods3"
+ ClassTransform ct = ClassTransform.dropping(
+ element -> element instanceof MethodModel mm
+ && mm.methodName().stringValue().startsWith("debug"));
+ // @end
+ }
+
void fooToBarTransform() {
// @start region="fooToBarTransform"
CodeTransform fooToBar = (b, e) -> {
@@ -199,7 +221,7 @@ class PackageSnippets {
CodeTransform instrumentCalls = (b, e) -> {
if (e instanceof InvokeInstruction i) {
b.getstatic(CD_System, "out", CD_PrintStream)
- .constantInstruction(Opcode.LDC, i.name().stringValue())
+ .ldc(i.name().stringValue())
.invokevirtual(CD_PrintStream, "println", MTD_void_String);
}
b.with(e);