diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFile.java b/src/java.base/share/classes/java/lang/classfile/ClassFile.java index db293f41588..6593dfcf2ae 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFile.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFile.java @@ -32,6 +32,8 @@ import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.classfile.instruction.BranchInstruction; +import java.lang.classfile.instruction.DiscontinuedInstruction; import java.lang.classfile.instruction.ExceptionCatch; import java.lang.constant.ClassDesc; import java.lang.reflect.AccessFlag; @@ -230,17 +232,35 @@ enum LineNumbersOption implements Option { /** * Option describing whether to automatically rewrite short jumps to * long when necessary. - * Default is {@code FIX_SHORT_JUMPS} to automatically rewrite jump + * Default is {@link #FIX_SHORT_JUMPS} to automatically rewrite jump * instructions. + *

+ * Due to physical restrictions, some types of instructions cannot encode + * certain jump targets with bci offsets less than -32768 or greater than + * 32767, as they use a {@code s2} to encode such an offset. (The maximum + * length of the {@code code} array is 65535.) These types of instructions + * are called "short jumps". * + * @see BranchInstruction + * @see DiscontinuedInstruction.JsrInstruction * @since 24 */ enum ShortJumpsOption implements Option { - /** Automatically convert short jumps to long when necessary */ + /** + * Automatically convert short jumps to long when necessary. + *

+ * For an invalid instruction model, a {@link CodeBuilder} may generate + * another or a few other instructions to accomplish the same effect. + */ FIX_SHORT_JUMPS, - /** Fail if short jump overflows */ + /** + * Fail with an {@link IllegalArgumentException} if short jump overflows. + *

+ * This is useful to ensure the physical accuracy of a generated {@code + * class} file. + */ FAIL_ON_SHORT_JUMPS } diff --git a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java index 1a074c1554a..3cbcb893cb1 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -51,7 +51,7 @@ * #with(ClassFileElement)} or concretely by calling the various {@code withXxx} * methods. * - *

Instruction Factories

+ *

Instruction Factories

* {@code CodeBuilder} provides convenience methods to create instructions (See * JVMS {@jvms 6.5} Instructions) by their mnemonic, taking necessary operands. * * - * @see java.lang.classfile.attribute.CharacterRangeInfo#flags() + * @see CharacterRangeInfo#flags() * * @return the flags */ diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ConstantInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/ConstantInstruction.java index 312c1868f19..f11a90c7d4c 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/ConstantInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ConstantInstruction.java @@ -24,6 +24,7 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; @@ -38,12 +39,22 @@ /** * Models a constant-load instruction in the {@code code} array of a {@code - * Code} attribute, including "intrinsic constant" instructions (e.g., {@code - * iconst_0}), "argument constant" instructions (e.g., {@code bipush}), and "load - * constant" instructions (e.g., {@code LDC}). Corresponding opcodes will have - * a {@code kind} of {@link Opcode.Kind#CONSTANT}. Delivered as a {@link - * CodeElement} when traversing the elements of a {@link CodeModel}. + * Code} attribute, including {@linkplain IntrinsicConstantInstruction + * "intrinsic"}, {@linkplain ArgumentConstantInstruction "argument"}, and + * {@linkplain LoadConstantInstruction "load"} constant instructions. + * Corresponding opcodes have a {@linkplain Opcode#kind() kind} of {@link + * Opcode.Kind#CONSTANT}. Delivered as a {@link CodeElement} when traversing + * the elements of a {@link CodeModel}. + *

+ * The loaded constant value is symbolically represented as a {@link ConstantDesc}: + * {@snippet lang=text : + * // @link substring="ConstantInstruction" target="CodeBuilder#loadConstant(ConstantDesc)" : + * ConstantInstruction(ConstantDesc constantValue) // @link substring="constantValue" target="#constantValue()" + * } * + * @see Opcode.Kind#CONSTANT + * @see CodeBuilder#loadConstant(ConstantDesc) CodeBuilder::loadConstant + * @sealedGraph * @since 24 */ public sealed interface ConstantInstruction extends Instruction { @@ -54,22 +65,36 @@ public sealed interface ConstantInstruction extends Instruction { ConstantDesc constantValue(); /** - * {@return the type of the constant} + * {@return the {@linkplain TypeKind##computational-type computational type} of the constant} + * This is derived from the {@link #constantValue() constantValue}. */ TypeKind typeKind(); /** - * Models an "intrinsic constant" instruction (e.g., {@code - * iconst_0}). + * Models an "intrinsic constant" instruction, which encodes + * the constant value in its opcode. Examples include {@link + * Opcode#ACONST_NULL aconst_null} and {@link + * Opcode#ICONST_0 iconst_0}. + *

+ * An intrinsic constant instruction is composite: + * {@snippet lang=text : + * // @link substring="IntrinsicConstantInstruction" target="#ofIntrinsic" : + * IntrinsicConstantInstruction(Opcode opcode) // @link substring="opcode" target="#opcode()" + * } + * where: + *

+ *
{@link #opcode() opcode}
+ *
Must be of the constant kind and have a {@linkplain + * Opcode#sizeIfFixed() fixed size} of 1.
+ *
* + * @see Opcode.Kind#CONSTANT + * @see ConstantInstruction#ofIntrinsic ConstantInstruction::ofIntrinsic * @since 24 */ sealed interface IntrinsicConstantInstruction extends ConstantInstruction permits AbstractInstruction.UnboundIntrinsicConstantInstruction { - /** - * {@return the type of the constant} - */ @Override default TypeKind typeKind() { return BytecodeHelpers.intrinsicConstantType(opcode()); @@ -77,9 +102,31 @@ default TypeKind typeKind() { } /** - * Models an "argument constant" instruction (e.g., {@code - * bipush}). + * Models an "argument constant" instruction, which encodes the + * constant value in the instruction directly. Includes {@link + * Opcode#BIPUSH bipush} and {@link Opcode#SIPUSH sipush} instructions. + *

+ * An argument constant instruction is composite: + * {@snippet lang=text : + * // @link substring="ArgumentConstantInstruction" target="#ofArgument" : + * ArgumentConstantInstruction( + * Opcode opcode, // @link substring="opcode" target="#opcode()" + * int constantValue // @link substring="constantValue" target="#constantValue()" + * ) + * } + * where: + *

* + * @see Opcode.Kind#CONSTANT + * @see ConstantInstruction#ofArgument ConstantInstruction::ofArgument + * @see CodeBuilder#loadConstant(int) CodeBuilder::loadConstant(int) + * @see CodeBuilder#bipush CodeBuilder::bipush + * @see CodeBuilder#sipush CodeBuilder::sipush * @since 24 */ sealed interface ArgumentConstantInstruction extends ConstantInstruction @@ -89,9 +136,6 @@ sealed interface ArgumentConstantInstruction extends ConstantInstruction @Override Integer constantValue(); - /** - * {@return the type of the constant} - */ @Override default TypeKind typeKind() { return TypeKind.INT; @@ -99,9 +143,24 @@ default TypeKind typeKind() { } /** - * Models a "load constant" instruction (e.g., {@code - * ldc}). + * Models a "load constant" instruction, which encodes the constant value + * in the constant pool. Includes {@link Opcode#LDC ldc} and {@link + * Opcode#LDC_W ldc_w}, and {@link Opcode#LDC2_W ldc2_w} instructions. + *

+ * A load constant instruction is composite: + * {@snippet lang=text : + * // @link substring="LoadConstantInstruction" target="CodeBuilder#ldc(LoadableConstantEntry)" : + * LoadConstantInstruction(LoadableConstantEntry constantEntry) // @link substring="constantEntry" target="#constantEntry()" + * } + *

+ * A "load constant" instruction can load any constant value supported by + * other constant-load instructions. However, other instructions are + * usually more optimized, avoiding extra constant pool entries and being + * smaller. * + * @see Opcode.Kind#CONSTANT + * @see ConstantInstruction#ofLoad ConstantInstruction::ofLoad + * @see CodeBuilder#ldc CodeBuilder::ldc * @since 24 */ sealed interface LoadConstantInstruction extends ConstantInstruction @@ -113,9 +172,6 @@ sealed interface LoadConstantInstruction extends ConstantInstruction */ LoadableConstantEntry constantEntry(); - /** - * {@return the type of the constant} - */ @Override default TypeKind typeKind() { return constantEntry().typeKind(); @@ -139,6 +195,10 @@ static IntrinsicConstantInstruction ofIntrinsic(Opcode op) { /** * {@return an argument constant instruction} + *

+ * {@code value} must be in the range of {@code byte}, {@code [-128, 127]}, + * for {@link Opcode#BIPUSH}, and in the range of {@code short}, {@code + * [-32768, 32767]}, for {@link Opcode#SIPUSH}. * * @param op the opcode for the specific type of argument constant instruction, * which must be {@link Opcode#BIPUSH} or {@link Opcode#SIPUSH} diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ConvertInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/ConvertInstruction.java index 468685779b9..0edffda1af1 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/ConvertInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ConvertInstruction.java @@ -24,6 +24,7 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; @@ -36,10 +37,27 @@ /** * Models a primitive conversion instruction in the {@code code} array of a - * {@code Code} attribute, such as {@code i2l}. Corresponding opcodes will have - * a {@code kind} of {@link Opcode.Kind#CONVERT}. Delivered as a {@link - * CodeElement} when traversing the elements of a {@link CodeModel}. + * {@code Code} attribute, such as {@link Opcode#I2L i2l}. Corresponding opcodes + * have a {@linkplain Opcode#kind() kind} of {@link Opcode.Kind#CONVERT}. + * Delivered as a {@link CodeElement} when traversing the elements of a {@link CodeModel}. + *

+ * A primitive conversion instruction is composite: + * {@snippet lang=text : + * // @link substring="ConvertInstruction" target="#of(TypeKind, TypeKind)" : + * ConvertInstruction( + * TypeKind fromType, // @link substring="fromType" target="#fromType" + * TypeKind toType // @link substring="toType" target="#toType" + * ) + * } + * where these conversions are valid: + *

* + * @see Opcode.Kind#CONVERT + * @see CodeBuilder#conversion CodeBuilder::conversion * @since 24 */ public sealed interface ConvertInstruction extends Instruction @@ -55,10 +73,16 @@ public sealed interface ConvertInstruction extends Instruction TypeKind toType(); /** - * {@return A conversion instruction} + * {@return a conversion instruction} Valid conversions are: + * * * @param fromType the type to convert from * @param toType the type to convert to + * @throws IllegalArgumentException if this is not a valid conversion */ static ConvertInstruction of(TypeKind fromType, TypeKind toType) { return of(BytecodeHelpers.convertOpcode(fromType, toType)); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java index 4e8ddcef385..4170e142ffe 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java @@ -24,32 +24,54 @@ */ package java.lang.classfile.instruction; -import java.lang.classfile.CodeElement; -import java.lang.classfile.CodeModel; -import java.lang.classfile.Instruction; -import java.lang.classfile.Label; -import java.lang.classfile.Opcode; +import java.lang.classfile.*; import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.BytecodeHelpers; import jdk.internal.classfile.impl.Util; /** - * Models instruction discontinued from the {@code code} array of a {@code Code} - * attribute. Delivered as a {@link CodeElement} when traversing the elements of - * a {@link CodeModel}. + * Marker interface for instruction discontinued from the {@code code} array of + * a {@code Code} attribute. Delivered as a {@link CodeElement} when traversing + * the elements of a {@link CodeModel}. * + * @apiNote + * While most instructions have convenience factory methods in {@link + * CodeBuilder}, discontinued instructions can only be supplied to code builders + * explicitly with {@link CodeBuilder#with CodeBuilder::with} to discourage + * their use. + * + * @jvms 4.9.1 Static Constraints + * @sealedGraph * @since 24 */ public sealed interface DiscontinuedInstruction extends Instruction { /** - * Models JSR and JSR_W instructions discontinued from the {@code code} - * array of a {@code Code} attribute since class file version 51.0. - * Corresponding opcodes will have a {@code kind} of - * {@link Opcode.Kind#DISCONTINUED_JSR}. Delivered as a {@link CodeElement} - * when traversing the elements of a {@link CodeModel}. + * Models jump subroutine instructions discontinued from the {@code code} + * array of a {@code Code} attribute since class file major version {@value + * ClassFile#JAVA_7_VERSION} (JVMS {@jvms 4.9.1}). Corresponding opcodes + * have a {@linkplain Opcode#kind() kind} of {@link Opcode.Kind#DISCONTINUED_JSR}. + * Delivered as a {@link CodeElement} when traversing the elements of a + * {@link CodeModel}. + *

+ * A jump subroutine instruction is composite: + * {@snippet lang=text : + * // @link substring="JsrInstruction" target="#of(Label)" : + * JsrInstruction(Label target) // @link substring="target" target="#target()" + * } + *

+ * Due to physical restrictions, {@link Opcode#JSR jsr} instructions cannot + * encode labels too far away in the list of code elements. In such cases, + * the {@link ClassFile.ShortJumpsOption} controls how an invalid {@code jsr} + * instruction model is written by a {@link CodeBuilder}. + *

+ * Jump subroutine instructions push a {@link TypeKind##returnAddress + * returnAddress} value to the operand stack, and {@link StoreInstruction + * astore} series of instructions can then store this value to a local + * variable slot. * + * @see Opcode.Kind#DISCONTINUED_JSR * @since 24 */ sealed interface JsrInstruction extends DiscontinuedInstruction @@ -57,14 +79,18 @@ sealed interface JsrInstruction extends DiscontinuedInstruction AbstractInstruction.UnboundJsrInstruction { /** - * {@return the target of the JSR instruction} + * {@return the target of the jump subroutine instruction} */ Label target(); /** - * {@return a JSR instruction} + * {@return a jump subroutine instruction} * - * @param op the opcode for the specific type of JSR instruction, + * @apiNote + * The explicit {@code op} argument allows creating {@link Opcode#JSR_W + * jsr_w} instructions to avoid short jumps. + * + * @param op the opcode for the specific type of jump subroutine instruction, * which must be of kind {@link Opcode.Kind#DISCONTINUED_JSR} * @param target target label of the subroutine * @throws IllegalArgumentException if the opcode kind is not @@ -76,7 +102,7 @@ static JsrInstruction of(Opcode op, Label target) { } /** - * {@return a JSR instruction} + * {@return a jump subroutine instruction} * * @param target target label of the subroutine */ @@ -86,12 +112,26 @@ static JsrInstruction of(Label target) { } /** - * Models RET and RET_W instructions discontinued from the {@code code} - * array of a {@code Code} attribute since class file version 51.0. - * Corresponding opcodes will have a {@code kind} of + * Models return from subroutine instructions discontinued from the {@code + * code} array of a {@code Code} attribute since class file major version + * {@value ClassFile#JAVA_7_VERSION} (JVMS {@jvms 4.9.1}). + * Corresponding opcodes have a {@linkplain Opcode#kind() kind} of * {@link Opcode.Kind#DISCONTINUED_RET}. Delivered as a {@link CodeElement} * when traversing the elements of a {@link CodeModel}. + *

+ * A return from subroutine instruction is composite: + * {@snippet lang=text : + * // @link substring="RetInstruction" target="#of(int)" : + * RetInstruction(int slot) // @link substring="slot" target="#slot()" + * } + * where {@code slot} must be within {@code [0, 65535]}. + *

+ * {@link StoreInstruction astore} series of instructions store a {@link + * TypeKind##returnAddress returnAddress} value to a local variable slot, + * making the slot usable by a return from subroutine instruction. * + * @jvms 6.5.ret ret + * @see Opcode.Kind#DISCONTINUED_RET * @since 24 */ sealed interface RetInstruction extends DiscontinuedInstruction @@ -100,13 +140,23 @@ sealed interface RetInstruction extends DiscontinuedInstruction /** * {@return the local variable slot with return address} + * The value is within {@code [0, 65535]}. */ int slot(); /** - * {@return a RET or RET_W instruction} + * {@return a return from subroutine instruction} + *

+ * {@code slot} must be in the closed range of {@code [0, 255]} for + * {@link Opcode#RET ret}, or within {@code [0, 65535]} for {@link + * Opcode#RET_W wide ret}. + * + * @apiNote + * The explicit {@code op} argument allows creating {@code wide ret} + * instructions with {@code slot} in the range of regular {@code ret} + * instructions. * - * @param op the opcode for the specific type of RET instruction, + * @param op the opcode for the specific type of return from subroutine instruction, * which must be of kind {@link Opcode.Kind#DISCONTINUED_RET} * @param slot the local variable slot to load return address from * @throws IllegalArgumentException if the opcode kind is not @@ -118,7 +168,9 @@ static RetInstruction of(Opcode op, int slot) { } /** - * {@return a RET instruction} + * {@return a return from subroutine instruction} + *

+ * {@code slot} must be within {@code [0, 65535]}. * * @param slot the local variable slot to load return address from * @throws IllegalArgumentException if {@code slot} is out of range diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java b/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java index 885f029d108..2a86c4bd09c 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java @@ -24,23 +24,37 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Label; import java.lang.classfile.PseudoInstruction; +import java.lang.classfile.attribute.CodeAttribute; import java.lang.classfile.constantpool.ClassEntry; import java.util.Optional; import jdk.internal.classfile.impl.AbstractPseudoInstruction; /** - * A pseudo-instruction modeling an entry in the exception table of a code - * attribute. Entries in the exception table model catch and finally blocks. - * Delivered as a {@link CodeElement} when traversing the contents - * of a {@link CodeModel}. - * - * @see PseudoInstruction + * A pseudo-instruction modeling an entry in the {@code exception_table} array + * of a {@link CodeAttribute Code} attribute. Catch (JVMS {@jvms 3.12}) and + * finally (JVMS {@jvms 3.14}) blocks in Java source code compile to exception + * table entries. Delivered as a {@link CodeElement} when traversing the + * contents of a {@link CodeModel}. + *

+ * An exception table entry is composite: + * {@snippet lang=text : + * // @link substring="ExceptionCatch" target="#of(Label, Label, Label, Optional)" : + * ExceptionCatch( + * Label handler, // @link substring="handler" target="#handler" + * Label tryStart, // @link substring="tryStart" target="#tryStart" + * Label tryEnd, // @link substring="tryEnd" target="#tryEnd" + * Optional catchType // @link substring="catchType" target="#catchType" + * ) + * } * + * @see CodeBuilder#exceptionCatch CodeBuilder::exceptionCatch + * @jvms 4.7.3 The {@code Code} Attribute * @since 24 */ public sealed interface ExceptionCatch extends PseudoInstruction @@ -61,8 +75,8 @@ public sealed interface ExceptionCatch extends PseudoInstruction Label tryEnd(); /** - * {@return the type of the exception to catch, or empty if this handler is - * unconditional} + * {@return the type of the exception to catch, or empty if this handler + * catches everything} */ Optional catchType(); @@ -80,10 +94,10 @@ static ExceptionCatch of(Label handler, Label tryStart, Label tryEnd, } /** - * {@return an exception table pseudo-instruction for an unconditional handler} + * {@return an exception table pseudo-instruction to catch everything} * @param handler the handler for the exception - * @param tryStart the beginning of the instruction range for the gaurded instructions - * @param tryEnd the end of the instruction range for the gaurded instructions + * @param tryStart the beginning of the instruction range for the guarded instructions + * @param tryEnd the end of the instruction range for the guarded instructions */ static ExceptionCatch of(Label handler, Label tryStart, Label tryEnd) { return new AbstractPseudoInstruction.ExceptionCatchImpl(handler, tryStart, tryEnd, (ClassEntry) null); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/FieldInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/FieldInstruction.java index b547abd18ab..68d56667957 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/FieldInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/FieldInstruction.java @@ -24,6 +24,7 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; @@ -40,10 +41,21 @@ /** * Models a field access instruction in the {@code code} array of a {@code Code} - * attribute. Corresponding opcodes will have a {@code kind} of {@link - * Opcode.Kind#FIELD_ACCESS}. Delivered as a {@link CodeElement} when + * attribute. Corresponding opcodes have a {@linkplain Opcode#kind() kind} + * of {@link Opcode.Kind#FIELD_ACCESS}. Delivered as a {@link CodeElement} when * traversing the elements of a {@link CodeModel}. + *

+ * A field access instruction is composite: + * {@snippet lang=text : + * // @link substring="FieldInstruction" target="#of(Opcode, FieldRefEntry)" : + * FieldInstruction( + * Opcode opcode, // @link substring="opcode" target="#opcode()" + * FieldRefEntry field, // @link substring="field" target="#field()" + * ) + * } * + * @see Opcode.Kind#FIELD_ACCESS + * @see CodeBuilder#fieldAccess CodeBuilder::fieldAccess * @since 24 */ public sealed interface FieldInstruction extends Instruction @@ -68,7 +80,11 @@ default Utf8Entry name() { } /** - * {@return the field descriptor of the field} + * {@return the field descriptor string of the field} + * + * @apiNote + * A symbolic descriptor for the type of the field is available through + * {@link #typeSymbol() typeSymbol()}. */ default Utf8Entry type() { return field().nameAndType().type(); @@ -103,6 +119,8 @@ static FieldInstruction of(Opcode op, FieldRefEntry field) { * @param owner the class holding the field * @param name the name of the field * @param type the field descriptor + * @throws IllegalArgumentException if the opcode kind is not + * {@link Opcode.Kind#FIELD_ACCESS}. */ static FieldInstruction of(Opcode op, ClassEntry owner, @@ -118,6 +136,8 @@ static FieldInstruction of(Opcode op, * which must be of kind {@link Opcode.Kind#FIELD_ACCESS} * @param owner the class holding the field * @param nameAndType the name and field descriptor of the field + * @throws IllegalArgumentException if the opcode kind is not + * {@link Opcode.Kind#FIELD_ACCESS}. */ static FieldInstruction of(Opcode op, ClassEntry owner, diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java index 7ea516c7cc5..a874ef0a954 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java @@ -24,6 +24,7 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; @@ -33,10 +34,27 @@ /** * Models a local variable increment instruction in the {@code code} array of a - * {@code Code} attribute. Corresponding opcodes will have a {@code kind} of - * {@link Opcode.Kind#INCREMENT}. Delivered as a {@link CodeElement} when + * {@code Code} attribute. Corresponding opcodes have a {@linkplain Opcode#kind() + * kind} of {@link Opcode.Kind#INCREMENT}. Delivered as a {@link CodeElement} when * traversing the elements of a {@link CodeModel}. + *

+ * A local variable increment instruction is composite: + * {@snippet lang=text : + * // @link substring="IncrementInstruction" target="#of" : + * IncrementInstruction( + * int slot, // @link substring="slot" target="#slot()" + * int constant // @link substring="constant" target="#constant()" + * ) + * } + * where + *

* + * @see Opcode.Kind#INCREMENT + * @see CodeBuilder#iinc CodeBuilder::iinc + * @jvms 6.5.iinc iinc * @since 24 */ public sealed interface IncrementInstruction extends Instruction @@ -54,6 +72,10 @@ public sealed interface IncrementInstruction extends Instruction /** * {@return an increment instruction} + * * * @param slot the local variable slot to increment * @param constant the value to increment by diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/InvokeDynamicInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/InvokeDynamicInstruction.java index 43907b2a518..7cad91b9d8d 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/InvokeDynamicInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/InvokeDynamicInstruction.java @@ -24,9 +24,11 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; +import java.lang.classfile.Opcode; import java.lang.classfile.constantpool.InvokeDynamicEntry; import java.lang.classfile.constantpool.LoadableConstantEntry; import java.lang.classfile.constantpool.Utf8Entry; @@ -40,10 +42,20 @@ import jdk.internal.classfile.impl.Util; /** - * Models an {@code invokedynamic} instruction in the {@code code} array of a - * {@code Code} attribute. Delivered as a {@link CodeElement} when traversing - * the elements of a {@link CodeModel}. + * Models a dynamically-computed call site invocation instruction in the + * {@code code} array of a {@code Code} attribute. The corresponding opcode is + * {@link Opcode#INVOKEDYNAMIC invokedynamic}. Delivered as a {@link + * CodeElement} when traversing the elements of a {@link CodeModel}. + *

+ * A dynamically-computed call site invocation instruction is composite: + * {@snippet lang=text : + * // @link substring="InvokeDynamicInstruction" target="#of" : + * InvokeDynamicInstruction(InvokeDynamicEntry invokedynamic) // @link substring="invokedynamic" target="#invokedynamic()" + * } * + * @see Opcode.Kind#INVOKE_DYNAMIC + * @see CodeBuilder#invokedynamic CodeBuilder::invokedynamic + * @jvms 6.5.invokedynamic invokedynamic * @since 24 */ public sealed interface InvokeDynamicInstruction extends Instruction @@ -62,6 +74,10 @@ default Utf8Entry name() { /** * {@return the invocation type of the call site} + * + * @apiNote + * A symbolic descriptor for the invocation typeis available through {@link + * #typeSymbol() typeSymbol()}. */ default Utf8Entry type() { return invokedynamic().type(); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java index 904a17375ac..50791cbd0ff 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java @@ -24,10 +24,12 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; import java.lang.classfile.Opcode; +import java.lang.classfile.TypeKind; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.InterfaceMethodRefEntry; import java.lang.classfile.constantpool.MemberRefEntry; @@ -42,10 +44,26 @@ /** * Models a method invocation instruction in the {@code code} array of a {@code - * Code} attribute, other than {@code invokedynamic}. Corresponding opcodes - * will have a {@code kind} of {@link Opcode.Kind#INVOKE}. Delivered as a - * {@link CodeElement} when traversing the elements of a {@link CodeModel}. + * Code} attribute, other than {@link InvokeDynamicInstruction invokedynamic}. + * Corresponding opcodes have a {@linkplain Opcode#kind() kind} of {@link Opcode.Kind#INVOKE}. + * Delivered as a {@link CodeElement} when traversing the elements of a {@link CodeModel}. + *

+ * A method invocation instruction is composite: + * {@snippet lang=text : + * // @link substring="InvokeInstruction" target="#of(Opcode, MemberRefEntry)" : + * InvokeInstruction( + * Opcode opcode, // @link substring="opcode" target="#opcode()" + * MethodRefEntry | InterfaceMethodRefEntry method) // @link substring="method" target="#method()" + * ) + * } + * where {@code method} must be an {@code InterfaceMethodRefEntry} for {@link + * Opcode#INVOKEINTERFACE invokeinterface} opcode, and must be a {@code + * MethodRefEntry} for {@link Opcode#INVOKEVIRTUAL invokevirtual} opcode. + * {@link Opcode#INVOKESTATIC invokestatic} and {@link Opcode#INVOKESPECIAL + * invokespecial} can have either type of entry for {@code method}. * + * @see Opcode.Kind#INVOKE + * @see CodeBuilder#invoke CodeBuilder::invoke * @since 24 */ public sealed interface InvokeInstruction extends Instruction @@ -57,18 +75,25 @@ public sealed interface InvokeInstruction extends Instruction MemberRefEntry method(); /** - * {@return whether the class holding the method is an interface} + * {@return whether the class or interface holding the method is an interface} */ boolean isInterface(); /** - * {@return the {@code count} value of an {@code invokeinterface} instruction, as defined in JVMS {@jvms 6.5} - * or {@code 0} for {@code invokespecial}, {@code invokestatic} and {@code invokevirtual} instructions} + * {@return the {@code count} value of an {@code invokeinterface} instruction, + * or {@code 0} for other instructions} + *

+ * For an {@code invokeinterface} instruction, this value must be equivalent + * to the sum of {@linkplain TypeKind#slotSize() slot sizes} of all arguments + * plus one, which is equal to the number of operand stack depth consumed by + * this interface method invocation instruction. + * + * @jvms 6.5.invokeinterface invokeinterface */ int count(); /** - * {@return the class holding the method} + * {@return the class or interface holding the method} */ default ClassEntry owner() { return method().owner(); @@ -82,7 +107,11 @@ default Utf8Entry name() { } /** - * {@return the method descriptor of the method} + * {@return the method descriptor string of the method} + * + * @apiNote + * A symbolic descriptor for the type of the method is available through + * {@link #typeSymbol() typeSymbol()}. */ default Utf8Entry type() { return method().nameAndType().type(); @@ -95,7 +124,6 @@ default MethodTypeDesc typeSymbol() { return Util.methodTypeSymbol(method().type()); } - /** * {@return an invocation instruction} * @@ -103,7 +131,7 @@ default MethodTypeDesc typeSymbol() { * which must be of kind {@link Opcode.Kind#INVOKE} * @param method a constant pool entry describing the method * @throws IllegalArgumentException if the opcode kind is not - * {@link Opcode.Kind#INVOKE}. + * {@link Opcode.Kind#INVOKE} */ static InvokeInstruction of(Opcode op, MemberRefEntry method) { Util.checkKind(op, Opcode.Kind.INVOKE); @@ -119,6 +147,8 @@ static InvokeInstruction of(Opcode op, MemberRefEntry method) { * @param name the name of the method * @param type the method descriptor * @param isInterface whether the class holding the method is an interface + * @throws IllegalArgumentException if the opcode kind is not + * {@link Opcode.Kind#INVOKE} */ static InvokeInstruction of(Opcode op, ClassEntry owner, @@ -136,6 +166,8 @@ static InvokeInstruction of(Opcode op, * @param owner the class holding the method * @param nameAndType the name and type of the method * @param isInterface whether the class holding the method is an interface + * @throws IllegalArgumentException if the opcode kind is not + * {@link Opcode.Kind#INVOKE} */ static InvokeInstruction of(Opcode op, ClassEntry owner, diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LabelTarget.java b/src/java.base/share/classes/java/lang/classfile/instruction/LabelTarget.java index bc1deffc98b..c5b49973133 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LabelTarget.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LabelTarget.java @@ -24,10 +24,13 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; +import java.lang.classfile.CodeTransform; import java.lang.classfile.Label; import java.lang.classfile.PseudoInstruction; +import java.lang.classfile.attribute.CodeAttribute; import jdk.internal.classfile.impl.LabelImpl; @@ -35,9 +38,28 @@ * A pseudo-instruction which indicates that the specified label corresponds to * the current position in the {@code Code} attribute. Delivered as a {@link * CodeElement} during traversal of the elements of a {@link CodeModel}. + *

+ * This can be used to inspect the target position of labels across {@linkplain + * CodeTransform transformations}, as {@linkplain CodeAttribute#labelToBci bci} + * is not stable. + *

+ * When passed to a {@link CodeBuilder}, this pseudo-instruction sets the + * specified label to be bound at the current position in the builder. + *

+ * By design, {@code LabelTarget} cannot be created by users and can only be + * read from a code model. Use {@link CodeBuilder#labelBinding + * CodeBuilder::labelBinding} to bind arbitrary labels to a {@code CodeBuilder}. + *

+ * For a {@code CodeBuilder cob}, a {@code LabelTarget lt}, these two calls are + * equivalent: + * {@snippet lang=java : + * cob.with(lt); // @link substring="with" target="CodeBuilder#with" + * // @link substring="labelBinding" target="CodeBuilder#labelBinding" : + * cob.labelBinding(lt.label()); // @link substring="label" target="#label" + * } * - * @see PseudoInstruction - * + * @see Label + * @see CodeBuilder#labelBinding CodeBuilder::labelBinding * @since 24 */ public sealed interface LabelTarget extends PseudoInstruction diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java b/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java index a9a497708c0..3f10a3ada0d 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java @@ -25,21 +25,42 @@ package java.lang.classfile.instruction; import java.lang.classfile.ClassFile; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.PseudoInstruction; +import java.lang.classfile.attribute.CodeAttribute; +import java.lang.classfile.attribute.LineNumberInfo; import java.lang.classfile.attribute.LineNumberTableAttribute; import jdk.internal.classfile.impl.LineNumberImpl; /** - * A pseudo-instruction which models a single entry in the - * {@link LineNumberTableAttribute}. Delivered as a {@link CodeElement} - * during traversal of the elements of a {@link CodeModel}, according to - * the setting of the {@link ClassFile.LineNumbersOption} option. + * A pseudo-instruction which indicates the code for a given line number starts + * after the current position in a {@link CodeAttribute Code} attribute. This + * models a single entry in the {@link LineNumberTableAttribute LineNumberTable} + * attribute. Delivered as a {@link CodeElement} during traversal of the + * elements of a {@link CodeModel}, according to the setting of the {@link + * ClassFile.LineNumbersOption} option. + *

+ * A line number entry is composite: + * {@snippet lang=text : + * // @link substring="LineNumber" target="#of" : + * LineNumber(int line) // @link substring="int line" target="#line" + * } + *

+ * Another model, {@link LineNumberInfo}, also models a line number entry; it + * has no dependency on a {@code CodeModel} and represents of bci values as + * {@code int}s instead of order of pseudo-instructions in the elements of a + * {@code CodeModel}, and is used as components of a {@link LineNumberTableAttribute}. * - * @see PseudoInstruction + * @apiNote + * Line numbers are represented with custom pseudo-instructions to avoid using + * labels, which usually indicate branching targets for the control flow. * + * @see LineNumberInfo + * @see CodeBuilder#lineNumber CodeBuilder::lineNumber + * @see ClassFile.LineNumbersOption * @since 24 */ public sealed interface LineNumber extends PseudoInstruction diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java index c499dcc9944..81961320be3 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java @@ -24,6 +24,7 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; @@ -36,10 +37,23 @@ /** * Models a local variable load instruction in the {@code code} array of a - * {@code Code} attribute. Corresponding opcodes will have a {@code kind} of - * {@link Opcode.Kind#LOAD}. Delivered as a {@link CodeElement} when - * traversing the elements of a {@link CodeModel}. + * {@code Code} attribute. Corresponding opcodes have a {@linkplain + * Opcode#kind() kind} of {@link Opcode.Kind#LOAD}. Delivered as a {@link + * CodeElement} when traversing the elements of a {@link CodeModel}. + *

+ * A local variable load instruction is composite: + * {@snippet lang=text : + * // @link substring="LoadInstruction" target="#of(TypeKind, int)" : + * LoadInstruction( + * TypeKind typeKind, // @link substring="typeKind" target="#typeKind" + * int slot // @link substring="slot" target="#slot" + * ) + * } + * where {@code TypeKind} is {@linkplain TypeKind##computational-type + * computational}, and {@code slot} is within {@code [0, 65535]}. * + * @see Opcode.Kind#LOAD + * @see CodeBuilder#loadLocal CodeBuilder::loadLocal * @since 24 */ public sealed interface LoadInstruction extends Instruction @@ -48,16 +62,21 @@ public sealed interface LoadInstruction extends Instruction /** * {@return the local variable slot to load from} + * The value is within {@code [0, 65535]}. */ int slot(); /** - * {@return the type of the value to be loaded} + * {@return the {@linkplain TypeKind##computational-type computational type} + * of the value to be loaded} */ TypeKind typeKind(); /** * {@return a local variable load instruction} + * {@code kind} is {@linkplain TypeKind#asLoadable() converted} to its + * computational type. + * {@code slot} must be within {@code [0, 65535]}. * * @param kind the type of the value to be loaded * @param slot the local variable slot to load from @@ -71,6 +90,20 @@ static LoadInstruction of(TypeKind kind, int slot) { /** * {@return a local variable load instruction} + *

+ * The range of {@code slot} is restricted by the {@code op} and its + * {@linkplain Opcode#sizeIfFixed() size}: + *

+ * + * @apiNote + * The explicit {@code op} argument allows creating {@code wide} or + * regular load instructions when the {@code slot} can be encoded + * with more optimized load instructions. * * @param op the opcode for the specific type of load instruction, * which must be of kind {@link Opcode.Kind#LOAD} diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java index 0f8cb672e51..f44a4e094f1 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java @@ -25,10 +25,12 @@ package java.lang.classfile.instruction; import java.lang.classfile.ClassFile; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Label; import java.lang.classfile.PseudoInstruction; +import java.lang.classfile.attribute.LocalVariableInfo; import java.lang.classfile.attribute.LocalVariableTableAttribute; import java.lang.classfile.constantpool.Utf8Entry; import java.lang.constant.ClassDesc; @@ -39,19 +41,45 @@ import jdk.internal.classfile.impl.Util; /** - * A pseudo-instruction which models a single entry in the - * {@link LocalVariableTableAttribute}. Delivered as a {@link CodeElement} - * during traversal of the elements of a {@link CodeModel}, according to - * the setting of the {@link ClassFile.DebugElementsOption} option. + * A pseudo-instruction which models a single entry in the {@link + * LocalVariableTableAttribute LocalVariableTable} attribute. Delivered as a + * {@link CodeElement} during traversal of the elements of a {@link CodeModel}, + * according to the setting of the {@link ClassFile.DebugElementsOption} option. + *

+ * A local variable entry is composite: + * {@snippet lang=text : + * // @link substring="LocalVariable" target="#of(int, String, ClassDesc, Label, Label)" : + * LocalVariable( + * int slot, // @link substring="slot" target="#slot" + * String name, // @link substring="name" target="#name" + * ClassDesc type, // @link substring="type" target="#type" + * Label startScope, // @link substring="startScope" target="#startScope" + * Label endScope // @link substring="endScope" target="#endScope" + * ) + * } + * Where {@code slot} is within {@code [0, 65535]}. + *

+ * Another model, {@link LocalVariableInfo}, also models a local variable + * entry; it has no dependency on a {@code CodeModel} and represents of bci + * values as {@code int}s instead of {@code Label}s, and is used as components + * of a {@link LocalVariableTableAttribute}. * - * @see PseudoInstruction + * @apiNote + * {@code LocalVariable} is used for all local variables in Java source code. + * If a local variable has a parameterized type, a type argument, or an array + * type of one of the previous types, a {@link LocalVariableType} should be + * created for that local variable as well. * + * @see LocalVariableInfo + * @see CodeBuilder#localVariable CodeBuilder::localVariable + * @see ClassFile.DebugElementsOption * @since 24 */ public sealed interface LocalVariable extends PseudoInstruction permits AbstractPseudoInstruction.UnboundLocalVariable, BoundLocalVariable { /** * {@return the local variable slot} + * The value is within {@code [0, 65535]}. */ int slot(); @@ -61,7 +89,11 @@ public sealed interface LocalVariable extends PseudoInstruction Utf8Entry name(); /** - * {@return the local variable field descriptor} + * {@return the local variable field descriptor string} + * + * @apiNote + * A symbolic descriptor for the type of the local variable is available + * through {@link #typeSymbol() typeSymbol()}. */ Utf8Entry type(); @@ -84,6 +116,7 @@ default ClassDesc typeSymbol() { /** * {@return a local variable pseudo-instruction} + * {@code slot} must be within {@code [0, 65535]}. * * @param slot the local variable slot * @param nameEntry the local variable name @@ -99,6 +132,7 @@ static LocalVariable of(int slot, Utf8Entry nameEntry, Utf8Entry descriptorEntry /** * {@return a local variable pseudo-instruction} + * {@code slot} must be within {@code [0, 65535]}. * * @param slot the local variable slot * @param name the local variable name diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java index c9427491733..1e28804a837 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java @@ -24,12 +24,8 @@ */ package java.lang.classfile.instruction; -import java.lang.classfile.ClassFile; -import java.lang.classfile.CodeElement; -import java.lang.classfile.CodeModel; -import java.lang.classfile.Label; -import java.lang.classfile.PseudoInstruction; -import java.lang.classfile.Signature; +import java.lang.classfile.*; +import java.lang.classfile.attribute.LocalVariableTypeInfo; import java.lang.classfile.attribute.LocalVariableTypeTableAttribute; import java.lang.classfile.constantpool.Utf8Entry; @@ -39,16 +35,44 @@ /** * A pseudo-instruction which models a single entry in the {@link - * LocalVariableTypeTableAttribute}. Delivered as a {@link CodeElement} during - * traversal of the elements of a {@link CodeModel}, according to the setting of - * the {@link ClassFile.DebugElementsOption} option. + * LocalVariableTypeTableAttribute LocalVariableTypeTable} attribute. Delivered + * as a {@link CodeElement} during traversal of the elements of a {@link CodeModel}, + * according to the setting of the {@link ClassFile.DebugElementsOption} option. + *

+ * A local variable type entry is composite: + * {@snippet lang=text : + * // @link substring="LocalVariableType" target="#of(int, String, Signature, Label, Label)" : + * LocalVariableType( + * int slot, // @link substring="slot" target="#slot" + * String name, // @link substring="name" target="#name" + * Signature signature, // @link substring="signature" target="#signatureSymbol" + * Label startScope, // @link substring="startScope" target="#startScope" + * Label endScope // @link substring="endScope" target="#endScope" + * ) + * } + * Where {@code slot} is within {@code [0, 65535]}. + *

+ * Another model, {@link LocalVariableTypeInfo}, also models a local variable + * type entry; it has no dependency on a {@code CodeModel} and represents of bci + * values as {@code int}s instead of {@code Label}s, and is used as components + * of a {@link LocalVariableTypeTableAttribute}. * + * @apiNote + * {@code LocalVariableType} is used if a local variable has a parameterized + * type, a type argument, or an array type of one of the previous types as its + * type. A {@link LocalVariable} with the erased type should still be created + * for that local variable. + * + * @see LocalVariableTypeInfo + * @see CodeBuilder#localVariableType CodeBuilder::localVariableType + * @see ClassFile.DebugElementsOption * @since 24 */ public sealed interface LocalVariableType extends PseudoInstruction permits AbstractPseudoInstruction.UnboundLocalVariableType, BoundLocalVariableType { /** * {@return the local variable slot} + * The value is within {@code [0, 65535]}. */ int slot(); @@ -58,12 +82,16 @@ public sealed interface LocalVariableType extends PseudoInstruction Utf8Entry name(); /** - * {@return the local variable signature} + * {@return the local variable generic signature string} + * + * @apiNote + * A symbolic generic signature of the local variable is available + * through {@link #signatureSymbol() signatureSymbol()}. */ Utf8Entry signature(); /** - * {@return the local variable signature} + * {@return the local variable generic signature} */ default Signature signatureSymbol() { return Signature.parseFrom(signature().stringValue()); @@ -81,6 +109,7 @@ default Signature signatureSymbol() { /** * {@return a local variable type pseudo-instruction} + * {@code slot} must be within {@code [0, 65535]}. * * @param slot the local variable slot * @param nameEntry the local variable name @@ -96,6 +125,7 @@ static LocalVariableType of(int slot, Utf8Entry nameEntry, Utf8Entry signatureEn /** * {@return a local variable type pseudo-instruction} + * {@code slot} must be within {@code [0, 65535]}. * * @param slot the local variable slot * @param name the local variable name diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LookupSwitchInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/LookupSwitchInstruction.java index 7b286e9cfd2..33e3ec002fd 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LookupSwitchInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LookupSwitchInstruction.java @@ -24,19 +24,36 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; import java.lang.classfile.Label; +import java.lang.classfile.Opcode; import java.util.List; import jdk.internal.classfile.impl.AbstractInstruction; /** - * Models a {@code lookupswitch} instruction in the {@code code} array of a - * {@code Code} attribute. Delivered as a {@link CodeElement} when traversing - * the elements of a {@link CodeModel}. + * Models a {@link Opcode#LOOKUPSWITCH lookupswitch} instruction in the {@code + * code} array of a {@code Code} attribute. Delivered as a {@link CodeElement} + * when traversing the elements of a {@link CodeModel}. + *

+ * A lookup switch instruction is composite: + * {@snippet lang=text : + * // @link substring="LookupSwitchInstruction" target="#of" : + * LookupSwitchInstruction( + * Label defaultTarget, // @link substring="defaultTarget" target="#defaultTarget" + * List cases // @link substring="cases" target="#cases()" + * ) + * } + * If elements in {@code cases} are not sorted ascending by their {@link + * SwitchCase#caseValue caseValue}, a sorted version of the {@code cases} list + * will be written instead. * + * @see Opcode.Kind#LOOKUP_SWITCH + * @see CodeBuilder#lookupswitch CodeBuilder::lookupswitch + * @jvms 6.5.lookupswitch lookupswitch * @since 24 */ public sealed interface LookupSwitchInstruction extends Instruction diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/MonitorInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/MonitorInstruction.java index 1c8268cddd6..0efdfbdb34f 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/MonitorInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/MonitorInstruction.java @@ -24,6 +24,7 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; @@ -33,9 +34,17 @@ import jdk.internal.classfile.impl.Util; /** - * Models a {@code monitorenter} or {@code monitorexit} instruction in the - * {@code code} array of a {@code Code} attribute. Delivered as a {@link - * CodeElement} when traversing the elements of a {@link CodeModel}. + * Models a {@link Opcode#MONITORENTER monitorenter} or {@link Opcode#MONITOREXIT + * monitorexit} instruction in the {@code code} array of a {@code Code} attribute. + * Corresponding opcodes have a {@linkplain Opcode#kind() kind} of {@link + * Opcode.Kind#MONITOR}. Delivered as a {@link CodeElement} when traversing the + * elements of a {@link CodeModel}. + *

+ * A monitor instruction is composite: + * {@snippet lang=text : + * // @link substring="MonitorInstruction" target="#of(Opcode)" : + * MonitorInstruction(Opcode opcode) // @link substring="opcode" target="#opcode" + * } * * @since 24 */ diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/NewMultiArrayInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/NewMultiArrayInstruction.java index 4a1f6cfd170..f7efd144422 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/NewMultiArrayInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/NewMultiArrayInstruction.java @@ -24,19 +24,34 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; +import java.lang.classfile.Opcode; import java.lang.classfile.constantpool.ClassEntry; import jdk.internal.classfile.impl.AbstractInstruction; import jdk.internal.classfile.impl.BytecodeHelpers; /** - * Models a {@code multianewarray} invocation instruction in the {@code code} + * Models a {@link Opcode#MULTIANEWARRAY multianewarray} instruction in the {@code code} * array of a {@code Code} attribute. Delivered as a {@link CodeElement} * when traversing the elements of a {@link CodeModel}. + *

+ * A new multi-dimensional array instruction is composite: + * {@snippet lang=text : + * // @link substring="NewMultiArrayInstruction" target="#of" : + * NewMultiArrayInstruction( + * ClassEntry arrayType, // @link substring="arrayType" target="#arrayType" + * int dimensions // @link substring="dimensions" target="#dimensions" + * ) + * } + * where the {@code arrayType} is an array class. * + * @see Opcode.Kind#NEW_MULTI_ARRAY + * @see CodeBuilder#multianewarray CodeBuilder::multianewarray + * @jvms 6.5.multianewarray multianewarray * @since 24 */ public sealed interface NewMultiArrayInstruction extends Instruction @@ -44,7 +59,7 @@ public sealed interface NewMultiArrayInstruction extends Instruction AbstractInstruction.UnboundNewMultidimensionalArrayInstruction { /** - * {@return the type of the array, as a symbolic descriptor} + * {@return the type of the array} */ ClassEntry arrayType(); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/NewObjectInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/NewObjectInstruction.java index f063733b64f..62b0233be87 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/NewObjectInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/NewObjectInstruction.java @@ -24,18 +24,30 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; +import java.lang.classfile.Opcode; import java.lang.classfile.constantpool.ClassEntry; import jdk.internal.classfile.impl.AbstractInstruction; /** - * Models a {@code new} instruction in the {@code code} array of a {@code Code} + * Models a {@link Opcode#NEW new} instruction in the {@code code} array of a {@code Code} * attribute. Delivered as a {@link CodeElement} when traversing the elements * of a {@link CodeModel}. + *

+ * A new object instruction is composite: + * {@snippet lang=text : + * // @link substring="NewObjectInstruction" target="#of" : + * NewObjectInstruction(ClassEntry className) // @link substring="className" target="#className" + * } + * where the {@code className} is a non-abstract class. * + * @see Opcode.Kind#NEW_OBJECT + * @see CodeBuilder#new_ CodeBuilder::new_ + * @jvms 6.5.new new * @since 24 */ public sealed interface NewObjectInstruction extends Instruction diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/NewPrimitiveArrayInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/NewPrimitiveArrayInstruction.java index 411bf7f6b55..c1e2c9d12fa 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/NewPrimitiveArrayInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/NewPrimitiveArrayInstruction.java @@ -24,18 +24,30 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; +import java.lang.classfile.Opcode; import java.lang.classfile.TypeKind; import jdk.internal.classfile.impl.AbstractInstruction; /** - * Models a {@code newarray} invocation instruction in the {@code code} + * Models a {@link Opcode#NEWARRAY newarray} instruction in the {@code code} * array of a {@code Code} attribute. Delivered as a {@link CodeElement} * when traversing the elements of a {@link CodeModel}. + *

+ * A new primitive array instruction is composite: + * {@snippet lang=text : + * // @link substring="NewPrimitiveArrayInstruction" target="#of" : + * NewPrimitiveArrayInstruction(TypeKind typeKind) // @link substring="typeKind" target="#typeKind" + * } + * where {@code typeKind} is primitive and not {@code void}. * + * @see Opcode.Kind#NEW_PRIMITIVE_ARRAY + * @see CodeBuilder#newarray CodeBuilder::newarray + * @jvms 6.5.newarray newarray * @since 24 */ public sealed interface NewPrimitiveArrayInstruction extends Instruction @@ -43,6 +55,10 @@ public sealed interface NewPrimitiveArrayInstruction extends Instruction AbstractInstruction.UnboundNewPrimitiveArrayInstruction { /** * {@return the component type of the array} + * + * @apiNote + * The backing array code for this instruction is available through + * {@link TypeKind#newarrayCode() typeKind().newarrayCode()}. */ TypeKind typeKind(); @@ -50,8 +66,9 @@ public sealed interface NewPrimitiveArrayInstruction extends Instruction * {@return a new primitive array instruction} * * @param typeKind the component type of the array - * @throws IllegalArgumentException when the {@code typeKind} is not a legal - * primitive array component type + * @throws IllegalArgumentException when {@code typeKind} is not primitive + * or is {@code void} + * @see TypeKind#fromNewarrayCode(int) TypeKind::fromNewarrayCode */ static NewPrimitiveArrayInstruction of(TypeKind typeKind) { // Implicit null-check: diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/NewReferenceArrayInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/NewReferenceArrayInstruction.java index c85ed9dd3d9..a092c068a36 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/NewReferenceArrayInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/NewReferenceArrayInstruction.java @@ -24,18 +24,29 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; +import java.lang.classfile.Opcode; import java.lang.classfile.constantpool.ClassEntry; import jdk.internal.classfile.impl.AbstractInstruction; /** - * Models a {@code anewarray} invocation instruction in the {@code code} + * Models a {@link Opcode#ANEWARRAY anewarray} instruction in the {@code code} * array of a {@code Code} attribute. Delivered as a {@link CodeElement} * when traversing the elements of a {@link CodeModel}. + *

+ * A new reference array instruction is composite: + * {@snippet lang=text : + * // @link substring="NewReferenceArrayInstruction" target="#of" : + * NewReferenceArrayInstruction(ClassEntry componentType) // @link substring="componentType" target="#componentType" + * } * + * @see Opcode.Kind#NEW_REF_ARRAY + * @see CodeBuilder#newarray CodeBuilder::anewarray + * @jvms 6.5.anewarray anewarray * @since 24 */ public sealed interface NewReferenceArrayInstruction extends Instruction diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/NopInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/NopInstruction.java index 3c11803109a..cf0b9f25ac9 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/NopInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/NopInstruction.java @@ -24,17 +24,23 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; +import java.lang.classfile.Opcode; import jdk.internal.classfile.impl.AbstractInstruction; /** - * Models a {@code nop} invocation instruction in the {@code code} + * Models a {@link Opcode#NOP nop} instruction in the {@code code} * array of a {@code Code} attribute. Delivered as a {@link CodeElement} * when traversing the elements of a {@link CodeModel}. + *

+ * A no-op instruction has no visible state. * + * @see CodeBuilder#nop CodeBuilder::nop + * @jvms 6.5.nop nop * @since 24 */ public sealed interface NopInstruction extends Instruction diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/OperatorInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/OperatorInstruction.java index d1eb8aa1a3d..b4daf55e3a5 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/OperatorInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/OperatorInstruction.java @@ -35,23 +35,31 @@ /** * Models an arithmetic operator instruction in the {@code code} array of a - * {@code Code} attribute. Corresponding opcodes will have a {@code kind} of + * {@code Code} attribute. Corresponding opcodes have a {@linkplain Opcode#kind() kind} of * {@link Opcode.Kind#OPERATOR}. Delivered as a {@link CodeElement} when * traversing the elements of a {@link CodeModel}. + *

+ * An operator instruction is composite: + * {@snippet lang=text : + * // @link substring="OperatorInstruction" target="#of" : + * OperatorInstruction(Opcode opcode) // @link substring="opcode" target="#opcode()" + * } * + * @see Opcode.Kind#OPERATOR * @since 24 */ public sealed interface OperatorInstruction extends Instruction permits AbstractInstruction.UnboundOperatorInstruction { /** * {@return the operand type of the instruction} + * This is derived from the {@link #opcode opcode}. */ TypeKind typeKind(); /** * {@return an operator instruction} * - * @param op the opcode for the specific type of array load instruction, + * @param op the opcode for the specific type of operator instruction, * which must be of kind {@link Opcode.Kind#OPERATOR} * @throws IllegalArgumentException if the opcode kind is not * {@link Opcode.Kind#OPERATOR}. diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ReturnInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/ReturnInstruction.java index 3bbb96b1cbe..aca9196eabf 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/ReturnInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ReturnInstruction.java @@ -24,6 +24,7 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; @@ -36,22 +37,35 @@ /** * Models a return-from-method instruction in the {@code code} array of a - * {@code Code} attribute. Corresponding opcodes will have a {@code kind} of + * {@code Code} attribute. Corresponding opcodes have a {@linkplain Opcode#kind() kind} of * {@link Opcode.Kind#RETURN}. Delivered as a {@link CodeElement} when * traversing the elements of a {@link CodeModel}. + *

+ * A return-from-method instruction is composite: + * {@snippet lang=text : + * // @link substring="ReturnInstruction" target="#of(TypeKind)" : + * ReturnInstruction(TypeKind typeKind) // @link substring="typeKind" target="#typeKind()" + * } + * where {@code typeKind} is {@linkplain TypeKind##computational-type + * computational} or {@link TypeKind#VOID void}. * + * @see Opcode.Kind#RETURN + * @see CodeBuilder#return_(TypeKind) CodeBuilder::return_ * @since 24 */ public sealed interface ReturnInstruction extends Instruction permits AbstractInstruction.UnboundReturnInstruction { /** - * {@return the type of the return instruction} + * {@return the {@linkplain TypeKind##computational-type computational type}, including + * {@link TypeKind#VOID void}, of the return instruction} */ TypeKind typeKind(); /** * {@return a return instruction} + * {@code typeKind} is {@linkplain TypeKind#asLoadable() converted} to its + * computational type. * * @param typeKind the type of the return instruction */ diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/StackInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/StackInstruction.java index b01b206e368..8ef413937bc 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/StackInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/StackInstruction.java @@ -34,10 +34,17 @@ /** * Models a stack manipulation instruction in the {@code code} array of a - * {@code Code} attribute. Corresponding opcodes will have a {@code kind} of + * {@code Code} attribute. Corresponding opcodes have a {@linkplain Opcode#kind() kind} of * {@link Opcode.Kind#STACK}. Delivered as a {@link CodeElement} when * traversing the elements of a {@link CodeModel}. + *

+ * A stack manipulation instruction is composite: + * {@snippet lang=text : + * // @link substring="StackInstruction" target="#of" : + * StackInstruction(Opcode opcode) // @link substring="opcode" target="#opcode()" + * } * + * @see Opcode.Kind#STACK * @since 24 */ public sealed interface StackInstruction extends Instruction diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java index 1d7bdce1fdf..93d33e0b7c2 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java @@ -24,6 +24,7 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; @@ -36,10 +37,28 @@ /** * Models a local variable store instruction in the {@code code} array of a - * {@code Code} attribute. Corresponding opcodes will have a {@code kind} of + * {@code Code} attribute. Corresponding opcodes have a {@linkplain Opcode#kind() kind} of * {@link Opcode.Kind#STORE}. Delivered as a {@link CodeElement} when * traversing the elements of a {@link CodeModel}. + *

+ * A local variable store instruction is composite: + * {@snippet lang=text : + * // @link substring="StoreInstruction" target="#of(TypeKind, int)" : + * StoreInstruction( + * TypeKind typeKind, // @link substring="typeKind" target="#typeKind" + * int slot // @link substring="slot" target="#slot" + * ) + * } + * where {@code TypeKind} is {@linkplain TypeKind##computational-type + * computational}, and {@code slot} is within {@code [0, 65535]}. + *

+ * {@code astore} series of instructions, or {@code reference} type store + * instructions, can also operate on the {@link TypeKind##returnAddress + * returnAddress} type from discontinued {@linkplain + * DiscontinuedInstruction.JsrInstruction jump subroutine instructions}. * + * @see Opcode.Kind#STORE + * @see CodeBuilder#storeLocal CodeBuilder::storeLocal * @since 24 */ public sealed interface StoreInstruction extends Instruction @@ -47,16 +66,23 @@ public sealed interface StoreInstruction extends Instruction /** * {@return the local variable slot to store to} + * The value is within {@code [0, 65535]}. */ int slot(); /** - * {@return the type of the value to be stored} + * {@return the {@linkplain TypeKind##computational-type computational type} + * of the value to be stored} The {@link TypeKind#REFERENCE reference} + * type store instructions also operate on the {@code returnAddress} type, + * which does not apply to {@code reference} type load instructions. */ TypeKind typeKind(); /** * {@return a local variable store instruction} + * {@code kind} is {@linkplain TypeKind#asLoadable() converted} to its + * computational type. + * {@code slot} must be within {@code [0, 65535]}. * * @param kind the type of the value to be stored * @param slot the local variable slot to store to @@ -70,6 +96,20 @@ static StoreInstruction of(TypeKind kind, int slot) { /** * {@return a local variable store instruction} + *

+ * The range of {@code slot} is restricted by the {@code op} and its + * {@linkplain Opcode#sizeIfFixed() size}: + *

+ * + * @apiNote + * The explicit {@code op} argument allows creating {@code wide} or + * regular store instructions when the {@code slot} can be encoded + * with more optimized store instructions. * * @param op the opcode for the specific type of store instruction, * which must be of kind {@link Opcode.Kind#STORE} diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/SwitchCase.java b/src/java.base/share/classes/java/lang/classfile/instruction/SwitchCase.java index 3f5f91031b6..cce8f8ef03a 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/SwitchCase.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/SwitchCase.java @@ -29,12 +29,20 @@ import jdk.internal.classfile.impl.AbstractInstruction; /** - * Models a single case in a {@code lookupswitch} or {@code tableswitch} - * instruction. + * Models a single case in a {@link LookupSwitchInstruction lookupswitch} or + * {@link TableSwitchInstruction tableswitch} instruction. + *

+ * A switch case is composite: + * {@snippet lang=text : + * // @link substring="SwitchCase" target="#of" : + * SwitchCase( + * int caseValue, // @link substring="caseValue" target="#caseValue" + * Label target // @link substring="target" target="#target" + * ) + * } * * @see LookupSwitchInstruction * @see TableSwitchInstruction - * * @since 24 */ public sealed interface SwitchCase @@ -47,11 +55,10 @@ public sealed interface SwitchCase Label target(); /** - * Create a {@linkplain SwitchCase} + * {@return a new switch case} * * @param caseValue the integer value for the case * @param target the branch target for the case - * @return the {@linkplain SwitchCase} */ static SwitchCase of(int caseValue, Label target) { return new AbstractInstruction.SwitchCaseImpl(caseValue, target); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/TableSwitchInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/TableSwitchInstruction.java index bbe7a4d6c0c..3f7245fad49 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/TableSwitchInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/TableSwitchInstruction.java @@ -24,19 +24,45 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; import java.lang.classfile.Label; +import java.lang.classfile.Opcode; import java.util.List; import jdk.internal.classfile.impl.AbstractInstruction; /** - * Models a {@code tableswitch} instruction in the {@code code} array of a + * Models a {@link Opcode#TABLESWITCH tableswitch} instruction in the {@code code} array of a * {@code Code} attribute. Delivered as a {@link CodeElement} when traversing * the elements of a {@link CodeModel}. + *

+ * A table switch instruction is composite: + * {@snippet lang=text : + * // @link substring="TableSwitchInstruction" target="#of" : + * TableSwitchInstruction( + * int lowValue, // @link substring="int lowValue" target="#lowValue" + * int highValue, // @link substring="int highValue" target="#highValue" + * Label defaultTarget, // @link substring="defaultTarget" target="#defaultTarget" + * List cases // @link substring="cases" target="#cases()" + * ) + * } + *

+ * When read from {@code class} files, the {@code cases} may omit cases that + * duplicate the default target. The list is sorted ascending by the {@link + * SwitchCase#caseValue() caseValue}. + *

+ * When writing to {@code class} file, the order in the {@code cases} list does + * not matter, as there is only one valid order in the physical representation + * of table switch entries. Treatment of elements in {@code cases} whose value + * is less than {@code lowValue} or greater than {@code highValue}, and elements + * whose value duplicates that of another, is not specified. * + * @see Opcode.Kind#TABLE_SWITCH + * @see CodeBuilder#tableswitch CodeBuilder::tableswitch + * @jvms 6.5.tableswitch tableswitch * @since 24 */ public sealed interface TableSwitchInstruction extends Instruction @@ -67,7 +93,8 @@ public sealed interface TableSwitchInstruction extends Instruction * @param lowValue the low value of the switch target range, inclusive * @param highValue the high value of the switch target range, inclusive * @param defaultTarget the default target of the switch - * @param cases the cases of the switch + * @param cases the cases of the switch; duplicate or out of bound case + * handling is not specified */ static TableSwitchInstruction of(int lowValue, int highValue, Label defaultTarget, List cases) { return new AbstractInstruction.UnboundTableSwitchInstruction(lowValue, highValue, defaultTarget, cases); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ThrowInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/ThrowInstruction.java index ec6fdc38626..4504b855c4c 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/ThrowInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ThrowInstruction.java @@ -24,17 +24,23 @@ */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.Instruction; +import java.lang.classfile.Opcode; import jdk.internal.classfile.impl.AbstractInstruction; /** - * Models an {@code athrow} instruction in the {@code code} array of a + * Models an {@link Opcode#ATHROW athrow} instruction in the {@code code} array of a * {@code Code} attribute. Delivered as a {@link CodeElement} when traversing * the elements of a {@link CodeModel}. + *

+ * A throw instruction has no visible state. * + * @see Opcode.Kind#THROW_EXCEPTION + * @see CodeBuilder#athrow CodeBuiler::athrow * @since 24 */ public sealed interface ThrowInstruction extends Instruction diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/TypeCheckInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/TypeCheckInstruction.java index 032e7a8462b..3091cf05e71 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/TypeCheckInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/TypeCheckInstruction.java @@ -36,9 +36,24 @@ import jdk.internal.classfile.impl.Util; /** - * Models an {@code instanceof} or {@code checkcast} instruction in the {@code - * code} array of a {@code Code} attribute. Delivered as a {@link CodeElement} - * when traversing the elements of a {@link CodeModel}. + * Models an {@link Opcode#INSTANCEOF instanceof} or a {@link Opcode#CHECKCAST checkcast} + * instruction in the {@code code} array of a {@code Code} attribute. Corresponding + * opcodes have a {@linkplain Opcode#kind() kind} of {@link Opcode.Kind#TYPE_CHECK}. + * Delivered as a {@link CodeElement} when traversing the elements of a {@link CodeModel}. + *

+ * An {@code instanceof} checks the type and pushes an integer to the operand stack. + * A {@code checkcast} checks the type and throws a {@link ClassCastException} if + * the check fails. {@code instanceof} treat the {@code null} reference as a + * failure, while {@code checkcast} treat the {@code null} reference as a success. + *

+ * A type check instruction is composite: + * {@snippet lang=text : + * // @link substring="TypeCheckInstruction" target="#of(Opcode, ClassEntry)" : + * TypeCheckInstruction( + * Opcode opcode, // @link substring="opcode" target="#opcode" + * ClassEntry type // @link substring="type" target="#type" + * ) + * } * * @since 24 */ @@ -47,7 +62,7 @@ public sealed interface TypeCheckInstruction extends Instruction AbstractInstruction.UnboundTypeCheckInstruction { /** - * {@return the type against which the instruction checks or casts} + * {@return the type against which the instruction checks} */ ClassEntry type(); @@ -58,7 +73,7 @@ public sealed interface TypeCheckInstruction extends Instruction * which must be of kind {@link Opcode.Kind#TYPE_CHECK} * @param type the type against which to check or cast * @throws IllegalArgumentException if the opcode kind is not - * {@link Opcode.Kind#TYPE_CHECK}. + * {@link Opcode.Kind#TYPE_CHECK} */ static TypeCheckInstruction of(Opcode op, ClassEntry type) { Util.checkKind(op, Opcode.Kind.TYPE_CHECK); @@ -71,6 +86,8 @@ static TypeCheckInstruction of(Opcode op, ClassEntry type) { * @param op the opcode for the specific type of type check instruction, * which must be of kind {@link Opcode.Kind#TYPE_CHECK} * @param type the type against which to check or cast + * @throws IllegalArgumentException if the opcode kind is not + * {@link Opcode.Kind#TYPE_CHECK}, or if {@code type} is primitive */ static TypeCheckInstruction of(Opcode op, ClassDesc type) { return of(op, TemporaryConstantPool.INSTANCE.classEntry(type)); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/package-info.java b/src/java.base/share/classes/java/lang/classfile/instruction/package-info.java index d2a36e16615..e732aadf1ec 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/package-info.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/package-info.java @@ -26,9 +26,45 @@ /** *

Provides interfaces describing code instructions for the {@link java.lang.classfile} library.

* - * The {@code java.lang.classfile.attribute} package contains interfaces describing code instructions. + * The {@code java.lang.classfile.instruction} package contains interfaces describing code instructions. + * Implementations of these interfaces are immutable. + *

+ * Unless otherwise specified, passing {@code null} or an array or collection containing a {@code null} element as an + * argument to a constructor or method of any Class-File API class or interface will cause a {@link NullPointerException} + * to be thrown. * + *

Reading of instructions

+ * Instructions and pseudo-instructions are usually accessed from a {@link CodeModel}, such as {@link CodeModel#forEach + * CodeModel::forEach}, and categorized by pattern-matching. + *

+ * When read from {@code class} files, instructions are lazily inflated; the contents of these instructions, besides the + * bare structure, are not evaluated to speed up parsing. Instructions to users interest, such as those filtered by the + * pattern matching, have their contents read on demand, to avoid unnecessary reading of unrelated instructions in a code + * array. + *

+ * Due to the lazy nature of {@code class} file parsing, {@link IllegalArgumentException} indicating malformed + * {@code class} file data can be thrown at any method invocation. For example, an instruction object for a {@link + * TypeCheckInstruction} may be obtained from a {@code CodeModel}, but the subsequent invocation of {@link + * TypeCheckInstruction#type() .type()} may fail with {@code IllegalArgumentException} because the instruction refers + * to a bad constant pool index. + * + *

Writing of instructions

+ * Writing of instructions happen on {@link CodeBuilder}. The most basic way to write instructions is to pass an + * instruction object to {@link CodeBuilder#with CodeBuilder::with}, which supports all valid instructions. + * Yet, {@code CodeBuilder} provides a lot of {@linkplain CodeBuilder##instruction-factories convenience factory methods} + * for easy creation of instructions, named by their mnemonic. These accessors are more concise, and often more + * efficient at run-time than passing instruction objects. + *

+ * Due to restrictions in the {@code class} file format, some instructions may not be representable in a {@code CodeBuilder}. + * In some scenarios, such as for {@link BranchInstruction}, Class-File API options control if alternatives can be used + * in code generation instead. Otherwise, they can be configured to fail-fast to ensure the parity of {@code CodeBuilder} + * commands with the generated {@code code} array data. + * + * @jvms 6.5 Instructions * @since 24 */ package java.lang.classfile.instruction; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.CodeModel; +