diff --git a/src/java.base/share/classes/jdk/internal/classfile/Attribute.java b/src/java.base/share/classes/jdk/internal/classfile/Attribute.java index 343ba9677e2..13df75e1514 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/Attribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/Attribute.java @@ -72,6 +72,7 @@ import jdk.internal.classfile.impl.UnboundAttribute; * corresponding model type. Additionally, all attributes are accessible * directly from the corresponding model type through {@link * AttributedElement#findAttribute(AttributeMapper)}. + * @param the attribute type */ public sealed interface Attribute> extends WritableElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/AttributeMapper.java b/src/java.base/share/classes/jdk/internal/classfile/AttributeMapper.java index eea5877a4e8..8892b56ed60 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/AttributeMapper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/AttributeMapper.java @@ -33,6 +33,7 @@ package jdk.internal.classfile; * attributes, clients can define their own {@linkplain AttributeMapper}. * Classes that model nonstandard attributes should extend {@link * CustomAttribute}. + * @param the attribute type */ public interface AttributeMapper { diff --git a/src/java.base/share/classes/jdk/internal/classfile/Attributes.java b/src/java.base/share/classes/jdk/internal/classfile/Attributes.java index 2a816e5df1b..699da664a9b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/Attributes.java +++ b/src/java.base/share/classes/jdk/internal/classfile/Attributes.java @@ -91,41 +91,113 @@ import jdk.internal.classfile.impl.StackMapDecoder; * @see AttributeMapper */ public class Attributes { + + /** AnnotationDefault */ public static final String NAME_ANNOTATION_DEFAULT = "AnnotationDefault"; + + /** BootstrapMethods */ public static final String NAME_BOOTSTRAP_METHODS = "BootstrapMethods"; + + /** CharacterRangeTable */ public static final String NAME_CHARACTER_RANGE_TABLE = "CharacterRangeTable"; + + /** Code */ public static final String NAME_CODE = "Code"; + + /** CompilationID */ public static final String NAME_COMPILATION_ID = "CompilationID"; + + /** ConstantValue */ public static final String NAME_CONSTANT_VALUE = "ConstantValue"; + + /** Deprecated */ public static final String NAME_DEPRECATED = "Deprecated"; + + /** EnclosingMethod */ public static final String NAME_ENCLOSING_METHOD = "EnclosingMethod"; + + /** Exceptions */ public static final String NAME_EXCEPTIONS = "Exceptions"; + + /** InnerClasses */ public static final String NAME_INNER_CLASSES = "InnerClasses"; + + /** LineNumberTable */ public static final String NAME_LINE_NUMBER_TABLE = "LineNumberTable"; + + /** LocalVariableTable */ public static final String NAME_LOCAL_VARIABLE_TABLE = "LocalVariableTable"; + + /** LocalVariableTypeTable */ public static final String NAME_LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable"; + + /** MethodParameters */ public static final String NAME_METHOD_PARAMETERS = "MethodParameters"; + + /** Module */ public static final String NAME_MODULE = "Module"; + + /** ModuleHashes */ public static final String NAME_MODULE_HASHES = "ModuleHashes"; + + /** ModuleMainClass */ public static final String NAME_MODULE_MAIN_CLASS = "ModuleMainClass"; + + /** ModulePackages */ public static final String NAME_MODULE_PACKAGES = "ModulePackages"; + + /** ModuleResolution */ public static final String NAME_MODULE_RESOLUTION = "ModuleResolution"; + + /** ModuleTarget */ public static final String NAME_MODULE_TARGET = "ModuleTarget"; + + /** NestHost */ public static final String NAME_NEST_HOST = "NestHost"; + + /** NestMembers */ public static final String NAME_NEST_MEMBERS = "NestMembers"; + + /** PermittedSubclasses */ public static final String NAME_PERMITTED_SUBCLASSES = "PermittedSubclasses"; + + /** Record */ public static final String NAME_RECORD = "Record"; + + /** RuntimeInvisibleAnnotations */ public static final String NAME_RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations"; + + /** RuntimeInvisibleTypeAnnotations */ public static final String NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = "RuntimeInvisibleParameterAnnotations"; + + /** */ public static final String NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = "RuntimeInvisibleTypeAnnotations"; + + /** RuntimeVisibleAnnotations */ public static final String NAME_RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations"; + + /** RuntimeVisibleParameterAnnotations */ public static final String NAME_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations"; + + /** RuntimeVisibleTypeAnnotations */ public static final String NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS = "RuntimeVisibleTypeAnnotations"; + + /** Signature */ public static final String NAME_SIGNATURE = "Signature"; + + /** SourceDebugExtension */ public static final String NAME_SOURCE_DEBUG_EXTENSION = "SourceDebugExtension"; + + /** SourceFile */ public static final String NAME_SOURCE_FILE = "SourceFile"; + + /** SourceID */ public static final String NAME_SOURCE_ID = "SourceID"; + + /** StackMapTable */ public static final String NAME_STACK_MAP_TABLE = "StackMapTable"; + + /** Synthetic */ public static final String NAME_SYNTHETIC = "Synthetic"; private Attributes() { @@ -712,7 +784,7 @@ public class Attributes { /** Attribute mapper for the {@code Synthetic} attribute */ public static final AttributeMapper - SYNTHETIC = new AbstractAttributeMapper<>(NAME_SYNTHETIC) { + SYNTHETIC = new AbstractAttributeMapper<>(NAME_SYNTHETIC, true) { @Override public SyntheticAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { return new BoundAttribute.BoundSyntheticAttribute(cf, this, p); diff --git a/src/java.base/share/classes/jdk/internal/classfile/ClassHierarchyResolver.java b/src/java.base/share/classes/jdk/internal/classfile/ClassHierarchyResolver.java index 94fba9b9ef5..f1c072a2f41 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/ClassHierarchyResolver.java +++ b/src/java.base/share/classes/jdk/internal/classfile/ClassHierarchyResolver.java @@ -48,8 +48,8 @@ import static java.lang.constant.ConstantDescs.CD_Object; public interface ClassHierarchyResolver { /** - * Returns a default instance of {@linkplain ClassHierarchyResolver} that - * gets {@link ClassHierarchyInfo} from system class loader with reflection. + * {@return the default instance of {@linkplain ClassHierarchyResolver} that + * gets {@link ClassHierarchyInfo} from system class loader with reflection} */ static ClassHierarchyResolver defaultResolver() { return ClassHierarchyImpl.DEFAULT_RESOLVER; diff --git a/src/java.base/share/classes/jdk/internal/classfile/Classfile.java b/src/java.base/share/classes/jdk/internal/classfile/Classfile.java index e7cc0628cbe..f8913f99b51 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/Classfile.java +++ b/src/java.base/share/classes/jdk/internal/classfile/Classfile.java @@ -96,6 +96,9 @@ public sealed interface Classfile return new ClassfileImpl.AttributeMapperOptionImpl(attributeMapper); } + /** + * {@return the function mapping attribute names to attribute mappers} + */ Function> attributeMapper(); } @@ -116,6 +119,9 @@ public sealed interface Classfile return new ClassfileImpl.ClassHierarchyResolverOptionImpl(classHierarchyResolver); } + /** + * {@return the class hierarchy resolver} + */ ClassHierarchyResolver classHierarchyResolver(); } @@ -129,7 +135,11 @@ public sealed interface Classfile * pool. */ enum ConstantPoolSharingOption implements Option { + + /** Preserves the original constant pool when transforming classfile */ SHARED_POOL, + + /** Creates a new constant pool when transforming classfile */ NEW_POOL } @@ -139,7 +149,11 @@ public sealed interface Classfile * code with NOPs. */ enum DeadCodeOption implements Option { + + /** Patch unreachable code */ PATCH_DEAD_CODE, + + /** Keep the unreachable code */ KEEP_DEAD_CODE } @@ -153,7 +167,11 @@ public sealed interface Classfile * elements instead. */ enum DeadLabelsOption implements Option { + + /** Fail on unresolved labels */ FAIL_ON_DEAD_LABELS, + + /** Filter unresolved labels */ DROP_DEAD_LABELS } @@ -165,7 +183,11 @@ public sealed interface Classfile * Default is {@code PASS_DEBUG} to process debug elements. */ enum DebugElementsOption implements Option { + + /** Process debug elements */ PASS_DEBUG, + + /** Drop debug elements */ DROP_DEBUG } @@ -176,7 +198,11 @@ public sealed interface Classfile * Default is {@code PASS_LINE_NUMBERS} to process line numbers. */ enum LineNumbersOption implements Option { + + /** Process line numbers */ PASS_LINE_NUMBERS, + + /** Drop line numbers */ DROP_LINE_NUMBERS; } @@ -187,7 +213,11 @@ public sealed interface Classfile * instructions. */ enum ShortJumpsOption implements Option { + + /** Automatically convert short jumps to long when necessary */ FIX_SHORT_JUMPS, + + /** Fail if short jump overflows */ FAIL_ON_SHORT_JUMPS } @@ -199,8 +229,14 @@ public sealed interface Classfile * @jvms 4.10.1 Verification by Type Checking */ enum StackMapsOption implements Option { + + /** Generate stack maps when required */ STACK_MAPS_WHEN_REQUIRED, + + /** Always generate stack maps */ GENERATE_STACK_MAPS, + + /** Drop stack maps from code */ DROP_STACK_MAPS } @@ -210,7 +246,11 @@ public sealed interface Classfile * attributes, and deliver as instances of {@link UnknownAttribute}. */ enum UnknownAttributesOption implements Option { + + /** Process unknown attributes */ PASS_UNKNOWN_ATTRIBUTES, + + /** Drop unknown attributes */ DROP_UNKNOWN_ATTRIBUTES } @@ -225,6 +265,7 @@ public sealed interface Classfile * Parse a classfile into a {@link ClassModel}. * @param path the path to the classfile * @return the class model + * @throws java.io.IOException */ default ClassModel parse(Path path) throws IOException { return parse(Files.readAllBytes(path)); @@ -260,6 +301,7 @@ public sealed interface Classfile * @param path the path to the file to write * @param thisClass the name of the class to build * @param handler a handler that receives a {@link ClassBuilder} + * @throws java.io.IOException */ default void buildTo(Path path, ClassDesc thisClass, @@ -275,6 +317,7 @@ public sealed interface Classfile * @param thisClassEntry the name of the class to build * @param constantPool the constant pool builder * @param handler a handler that receives a {@link ClassBuilder} + * @throws java.io.IOException */ default void buildTo(Path path, ClassEntry thisClassEntry, @@ -311,6 +354,7 @@ public sealed interface Classfile * Build a module descriptor into a file. * @param path the file to write * @param moduleAttribute the {@code Module} attribute + * @throws java.io.IOException */ default void buildModuleTo(Path path, ModuleAttribute moduleAttribute) throws IOException { @@ -322,6 +366,7 @@ public sealed interface Classfile * @param path the file to write * @param moduleAttribute the {@code Module} attribute * @param handler a handler that receives a {@link ClassBuilder} + * @throws java.io.IOException */ default void buildModuleTo(Path path, ModuleAttribute moduleAttribute, @@ -343,7 +388,7 @@ public sealed interface Classfile * b -> b.transform(model, transform)); * } * - * @param model class model to transform + * @param model the class model to transform * @param transform the transform * @return the bytes of the new class */ @@ -351,343 +396,1007 @@ public sealed interface Classfile return transform(model, model.thisClass(), transform); } + /** + * Transform one classfile into a new classfile with the aid of a + * {@link ClassTransform}. The transform will receive each element of + * this class, as well as a {@link ClassBuilder} for building the new class. + * The transform is free to preserve, remove, or replace elements as it + * sees fit. + * + * @param model the class model to transform + * @param newClassName new class name + * @param transform the transform + * @return the bytes of the new class + */ default byte[] transform(ClassModel model, ClassDesc newClassName, ClassTransform transform) { return transform(model, TemporaryConstantPool.INSTANCE.classEntry(newClassName), transform); } + /** + * Transform one classfile into a new classfile with the aid of a + * {@link ClassTransform}. The transform will receive each element of + * this class, as well as a {@link ClassBuilder} for building the new class. + * The transform is free to preserve, remove, or replace elements as it + * sees fit. + * + * @implNote + * This method behaves as if: + * {@snippet lang=java : + * this.build(newClassName, ConstantPoolBuilder.of(model), + * b -> b.transform(model, transform)); + * } + * + * @param model the class model to transform + * @param newClassName new class name + * @param transform the transform + * @return the bytes of the new class + */ byte[] transform(ClassModel model, ClassEntry newClassName, ClassTransform transform); + /** 0xCAFEBABE */ int MAGIC_NUMBER = 0xCAFEBABE; + /** 0 */ int NOP = 0; + + /** 1 */ int ACONST_NULL = 1; + + /** 2 */ int ICONST_M1 = 2; + + /** 3 */ int ICONST_0 = 3; + + /** 4 */ int ICONST_1 = 4; + + /** 5 */ int ICONST_2 = 5; + + /** 6 */ int ICONST_3 = 6; + + /** 7 */ int ICONST_4 = 7; + + /** 8 */ int ICONST_5 = 8; + + /** 9 */ int LCONST_0 = 9; + + /** 10 */ int LCONST_1 = 10; + + /** 11 */ int FCONST_0 = 11; + + /** 12 */ int FCONST_1 = 12; + + /** 13 */ int FCONST_2 = 13; + + /** 14 */ int DCONST_0 = 14; + + /** 15 */ int DCONST_1 = 15; + + /** 16 */ int BIPUSH = 16; + + /** 17 */ int SIPUSH = 17; + + /** 18 */ int LDC = 18; + + /** 19 */ int LDC_W = 19; + + /** 20 */ int LDC2_W = 20; + + /** 21 */ int ILOAD = 21; + + /** 22 */ int LLOAD = 22; + + /** 23 */ int FLOAD = 23; + + /** 24 */ int DLOAD = 24; + + /** 25 */ int ALOAD = 25; + + /** 26 */ int ILOAD_0 = 26; + + /** 27 */ int ILOAD_1 = 27; + + /** 28 */ int ILOAD_2 = 28; + + /** 29 */ int ILOAD_3 = 29; + + /** 30 */ int LLOAD_0 = 30; + + /** 31 */ int LLOAD_1 = 31; + + /** 32 */ int LLOAD_2 = 32; + + /** 33 */ int LLOAD_3 = 33; + + /** 34 */ int FLOAD_0 = 34; + + /** 35 */ int FLOAD_1 = 35; + + /** 36 */ int FLOAD_2 = 36; + + /** 37 */ int FLOAD_3 = 37; + + /** 38 */ int DLOAD_0 = 38; + + /** 39 */ int DLOAD_1 = 39; + + /** 40 */ int DLOAD_2 = 40; + + /** 41 */ int DLOAD_3 = 41; + + /** 42 */ int ALOAD_0 = 42; + + /** 43 */ int ALOAD_1 = 43; + + /** 44 */ int ALOAD_2 = 44; + + /** 45 */ int ALOAD_3 = 45; + + /** 46 */ int IALOAD = 46; + + /** 47 */ int LALOAD = 47; + + /** 48 */ int FALOAD = 48; + + /** 49 */ int DALOAD = 49; + + /** 50 */ int AALOAD = 50; + + /** 51 */ int BALOAD = 51; + + /** 52 */ int CALOAD = 52; + + /** 53 */ int SALOAD = 53; + + /** 54 */ int ISTORE = 54; + + /** 55 */ int LSTORE = 55; + + /** 56 */ int FSTORE = 56; + + /** 57 */ int DSTORE = 57; + + /** 58 */ int ASTORE = 58; + + /** 59 */ int ISTORE_0 = 59; + + /** 60 */ int ISTORE_1 = 60; + + /** 61 */ int ISTORE_2 = 61; + + /** 62 */ int ISTORE_3 = 62; + + /** 63 */ int LSTORE_0 = 63; + + /** 64 */ int LSTORE_1 = 64; + + /** 65 */ int LSTORE_2 = 65; + + /** 66 */ int LSTORE_3 = 66; + + /** 67 */ int FSTORE_0 = 67; + + /** 68 */ int FSTORE_1 = 68; + + /** 69 */ int FSTORE_2 = 69; + + /** 70 */ int FSTORE_3 = 70; + + /** 71 */ int DSTORE_0 = 71; + + /** 72 */ int DSTORE_1 = 72; + + /** 73 */ int DSTORE_2 = 73; + + /** 74 */ int DSTORE_3 = 74; + + /** 75 */ int ASTORE_0 = 75; + + /** 76 */ int ASTORE_1 = 76; + + /** 77 */ int ASTORE_2 = 77; + + /** 78 */ int ASTORE_3 = 78; + + /** 79 */ int IASTORE = 79; + + /** 80 */ int LASTORE = 80; + + /** 81 */ int FASTORE = 81; + + /** 82 */ int DASTORE = 82; + + /** 83 */ int AASTORE = 83; + + /** 84 */ int BASTORE = 84; + + /** 85 */ int CASTORE = 85; + + /** 86 */ int SASTORE = 86; + + /** 87 */ int POP = 87; + + /** 88 */ int POP2 = 88; + + /** 89 */ int DUP = 89; + + /** 90 */ int DUP_X1 = 90; + + /** 91 */ int DUP_X2 = 91; + + /** 92 */ int DUP2 = 92; + + /** 93 */ int DUP2_X1 = 93; + + /** 94 */ int DUP2_X2 = 94; + + /** 95 */ int SWAP = 95; + + /** 96 */ int IADD = 96; + + /** 97 */ int LADD = 97; + + /** 98 */ int FADD = 98; + + /** 99 */ int DADD = 99; + + /** 100 */ int ISUB = 100; + + /** 101 */ int LSUB = 101; + + /** 102 */ int FSUB = 102; + + /** 103 */ int DSUB = 103; + + /** 104 */ int IMUL = 104; + + /** 105 */ int LMUL = 105; + + /** 106 */ int FMUL = 106; + + /** 107 */ int DMUL = 107; + + /** 108 */ int IDIV = 108; + + /** 109 */ int LDIV = 109; + + /** 110 */ int FDIV = 110; + + /** 111 */ int DDIV = 111; + + /** 112 */ int IREM = 112; + + /** 113 */ int LREM = 113; + + /** 114 */ int FREM = 114; + + /** 115 */ int DREM = 115; + + /** 116 */ int INEG = 116; + + /** 117 */ int LNEG = 117; + + /** 118 */ int FNEG = 118; + + /** 119 */ int DNEG = 119; + + /** 120 */ int ISHL = 120; + + /** 121 */ int LSHL = 121; + + /** 122 */ int ISHR = 122; + + /** 123 */ int LSHR = 123; + + /** 124 */ int IUSHR = 124; + + /** 125 */ int LUSHR = 125; + + /** 126 */ int IAND = 126; + + /** 127 */ int LAND = 127; + + /** 128 */ int IOR = 128; + + /** 129 */ int LOR = 129; + + /** 130 */ int IXOR = 130; + + /** 131 */ int LXOR = 131; + + /** 132 */ int IINC = 132; + + /** 133 */ int I2L = 133; + + /** 134 */ int I2F = 134; + + /** 135 */ int I2D = 135; + + /** 136 */ int L2I = 136; + + /** 137 */ int L2F = 137; + + /** 138 */ int L2D = 138; + + /** 139 */ int F2I = 139; + + /** 140 */ int F2L = 140; + + /** 141 */ int F2D = 141; + + /** 142 */ int D2I = 142; + + /** 143 */ int D2L = 143; + + /** 144 */ int D2F = 144; + + /** 145 */ int I2B = 145; + + /** 146 */ int I2C = 146; + + /** 147 */ int I2S = 147; + + /** 148 */ int LCMP = 148; + + /** 149 */ int FCMPL = 149; + + /** 150 */ int FCMPG = 150; + + /** 151 */ int DCMPL = 151; + + /** 152 */ int DCMPG = 152; + + /** 153 */ int IFEQ = 153; + + /** 154 */ int IFNE = 154; + + /** 155 */ int IFLT = 155; + + /** 156 */ int IFGE = 156; + + /** 157 */ int IFGT = 157; + + /** 158 */ int IFLE = 158; + + /** 159 */ int IF_ICMPEQ = 159; + + /** 160 */ int IF_ICMPNE = 160; + + /** 161 */ int IF_ICMPLT = 161; + + /** 162 */ int IF_ICMPGE = 162; + + /** 163 */ int IF_ICMPGT = 163; + + /** 164 */ int IF_ICMPLE = 164; + + /** 165 */ int IF_ACMPEQ = 165; + + /** 166 */ int IF_ACMPNE = 166; + + /** 167 */ int GOTO = 167; + + /** 168 */ int JSR = 168; + + /** 169 */ int RET = 169; + + /** 170 */ int TABLESWITCH = 170; + + /** 171 */ int LOOKUPSWITCH = 171; + + /** 172 */ int IRETURN = 172; + + /** 173 */ int LRETURN = 173; + + /** 174 */ int FRETURN = 174; + + /** 175 */ int DRETURN = 175; + + /** 176 */ int ARETURN = 176; + + /** 177 */ int RETURN = 177; + + /** 178 */ int GETSTATIC = 178; + + /** 179 */ int PUTSTATIC = 179; + + /** 180 */ int GETFIELD = 180; + + /** 181 */ int PUTFIELD = 181; + + /** 182 */ int INVOKEVIRTUAL = 182; + + /** 183 */ int INVOKESPECIAL = 183; + + /** 184 */ int INVOKESTATIC = 184; + + /** 185 */ int INVOKEINTERFACE = 185; + + /** 186 */ int INVOKEDYNAMIC = 186; + + /** 187 */ int NEW = 187; + + /** 188 */ int NEWARRAY = 188; + + /** 189 */ int ANEWARRAY = 189; + + /** 190 */ int ARRAYLENGTH = 190; + + /** 191 */ int ATHROW = 191; + + /** 192 */ int CHECKCAST = 192; + + /** 193 */ int INSTANCEOF = 193; + + /** 194 */ int MONITORENTER = 194; + + /** 195 */ int MONITOREXIT = 195; + + /** 196 */ int WIDE = 196; + + /** 197 */ int MULTIANEWARRAY = 197; + + /** 198 */ int IFNULL = 198; + + /** 199 */ int IFNONNULL = 199; + + /** 200 */ int GOTO_W = 200; + + /** 201 */ int JSR_W = 201; + /** 0x0001 */ int ACC_PUBLIC = 0x0001; + + /** 0x0004 */ int ACC_PROTECTED = 0x0004; + + /** 0x0002 */ int ACC_PRIVATE = 0x0002; + + /** 0x0200 */ int ACC_INTERFACE = 0x0200; + + /** 0x4000 */ int ACC_ENUM = 0x4000; + + /** 0x2000 */ int ACC_ANNOTATION = 0x2000; + + /** 0x0020 */ int ACC_SUPER = 0x0020; + + /** 0x0400 */ int ACC_ABSTRACT = 0x0400; + + /** 0x0040 */ int ACC_VOLATILE = 0x0040; + + /** 0x0080 */ int ACC_TRANSIENT = 0x0080; + + /** 0x1000 */ int ACC_SYNTHETIC = 0x1000; + + /** 0x0008 */ int ACC_STATIC = 0x0008; + + /** 0x0010 */ int ACC_FINAL = 0x0010; + + /** 0x0020 */ int ACC_SYNCHRONIZED = 0x0020; + + /** 0x0040 */ int ACC_BRIDGE = 0x0040; + + /** 0x0080 */ int ACC_VARARGS = 0x0080; + + /** 0x0100 */ int ACC_NATIVE = 0x0100; + + /** 0x0800 */ int ACC_STRICT = 0x0800; + + /** 0x8000 */ int ACC_MODULE = 0x8000; + + /** 0x20 */ int ACC_OPEN = 0x20; + + /** 0x8000 */ int ACC_MANDATED = 0x8000; + + /** 0x20 */ int ACC_TRANSITIVE = 0x20; + + /** 0x40 */ int ACC_STATIC_PHASE = 0x40; + /** 0x0001 */ int CRT_STATEMENT = 0x0001; + + /** 0x0002 */ int CRT_BLOCK = 0x0002; + + /** 0x0004 */ int CRT_ASSIGNMENT = 0x0004; + + /** 0x0008 */ int CRT_FLOW_CONTROLLER = 0x0008; + + /** 0x0010 */ int CRT_FLOW_TARGET = 0x0010; + + /** 0x0020 */ int CRT_INVOKE = 0x0020; + + /** 0x0040 */ int CRT_CREATE = 0x0040; + + /** 0x0080 */ int CRT_BRANCH_TRUE = 0x0080; + + /** 0x0100 */ int CRT_BRANCH_FALSE = 0x0100; + /** 7 */ int TAG_CLASS = 7; + + /** 17 */ int TAG_CONSTANTDYNAMIC = 17; + + /** 6 */ int TAG_DOUBLE = 6; + + /** 9 */ int TAG_FIELDREF = 9; + + /** 4 */ int TAG_FLOAT = 4; + + /** 3 */ int TAG_INTEGER = 3; + + /** 11 */ int TAG_INTERFACEMETHODREF = 11; + + /** 18 */ int TAG_INVOKEDYNAMIC = 18; + + /** 5 */ int TAG_LONG = 5; + + /** 15 */ int TAG_METHODHANDLE = 15; + + /** 10 */ int TAG_METHODREF = 10; + + /** 16 */ int TAG_METHODTYPE = 16; + + /** 19 */ int TAG_MODULE = 19; + + /** 12 */ int TAG_NAMEANDTYPE = 12; + + /** 20 */ int TAG_PACKAGE = 20; + + /** 8 */ int TAG_STRING = 8; + + /** 2 */ int TAG_UNICODE = 2; + + /** 1 */ int TAG_UTF8 = 1; // annotation element values + + /** 'B' */ char AEV_BYTE = 'B'; + + /** 'C' */ char AEV_CHAR = 'C'; + + /** 'D' */ char AEV_DOUBLE = 'D'; + + /** 'F' */ char AEV_FLOAT = 'F'; + + /** 'I' */ char AEV_INT = 'I'; + + /** 'J' */ char AEV_LONG = 'J'; + + /** 'S' */ char AEV_SHORT = 'S'; + + /** 'Z' */ char AEV_BOOLEAN = 'Z'; + + /** 's' */ char AEV_STRING = 's'; + + /** 'e' */ char AEV_ENUM = 'e'; + + /** 'c' */ char AEV_CLASS = 'c'; + + /** '@' */ char AEV_ANNOTATION = '@'; + + /** '[' */ char AEV_ARRAY = '['; //type annotations + + /** 0x00 */ int TAT_CLASS_TYPE_PARAMETER = 0x00; + + /** 0x01 */ int TAT_METHOD_TYPE_PARAMETER = 0x01; + + /** 0x10 */ int TAT_CLASS_EXTENDS = 0x10; + + /** 0x11 */ int TAT_CLASS_TYPE_PARAMETER_BOUND = 0x11; + + /** 0x12 */ int TAT_METHOD_TYPE_PARAMETER_BOUND = 0x12; + + /** 0x13 */ int TAT_FIELD = 0x13; + + /** 0x14 */ int TAT_METHOD_RETURN = 0x14; + + /** 0x15 */ int TAT_METHOD_RECEIVER = 0x15; + + /** 0x16 */ int TAT_METHOD_FORMAL_PARAMETER = 0x16; + + /** 0x17 */ int TAT_THROWS = 0x17; + + /** 0x40 */ int TAT_LOCAL_VARIABLE = 0x40; + + /** 0x41 */ int TAT_RESOURCE_VARIABLE = 0x41; + + /** 0x42 */ int TAT_EXCEPTION_PARAMETER = 0x42; + + /** 0x43 */ int TAT_INSTANCEOF = 0x43; + + /** 0x44 */ int TAT_NEW = 0x44; + + /** 0x45 */ int TAT_CONSTRUCTOR_REFERENCE = 0x45; + + /** 0x46 */ int TAT_METHOD_REFERENCE = 0x46; + + /** 0x47 */ int TAT_CAST = 0x47; + + /** 0x48 */ int TAT_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; + + /** 0x49 */ int TAT_METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; + + /** 0x4A */ int TAT_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; + + /** 0x4B */ int TAT_METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; //stackmap verification types + + /** 0 */ int VT_TOP = 0; + + /** 1 */ int VT_INTEGER = 1; + + /** 2 */ int VT_FLOAT = 2; + + /** 3 */ int VT_DOUBLE = 3; + + /** 4 */ int VT_LONG = 4; + + /** 5 */ int VT_NULL = 5; + + /** 6 */ int VT_UNINITIALIZED_THIS = 6; + + /** 7 */ int VT_OBJECT = 7; + + /** 8 */ int VT_UNINITIALIZED = 8; + /** ACC_PUBLIC */ int DEFAULT_CLASS_FLAGS = ACC_PUBLIC; + /** 45 */ int JAVA_1_VERSION = 45; + + /** 46 */ int JAVA_2_VERSION = 46; + + /** 47 */ int JAVA_3_VERSION = 47; + + /** 48 */ int JAVA_4_VERSION = 48; + + /** 49 */ int JAVA_5_VERSION = 49; + + /** 50 */ int JAVA_6_VERSION = 50; + + /** 51 */ int JAVA_7_VERSION = 51; + + /** 52 */ int JAVA_8_VERSION = 52; + + /** 53 */ int JAVA_9_VERSION = 53; + + /** 54 */ int JAVA_10_VERSION = 54; + + /** 55 */ int JAVA_11_VERSION = 55; + + /** 56 */ int JAVA_12_VERSION = 56; + + /** 57 */ int JAVA_13_VERSION = 57; + + /** 58 */ int JAVA_14_VERSION = 58; + + /** 59 */ int JAVA_15_VERSION = 59; + + /** 60 */ int JAVA_16_VERSION = 60; + + /** 61 */ int JAVA_17_VERSION = 61; + + /** 62 */ int JAVA_18_VERSION = 62; + + /** 63 */ int JAVA_19_VERSION = 63; + + /** 64 */ int JAVA_20_VERSION = 64; + + /** 65 */ int JAVA_21_VERSION = 65; + + /** 66 */ int JAVA_22_VERSION = 66; /** @@ -697,10 +1406,16 @@ public sealed interface Classfile */ int PREVIEW_MINOR_VERSION = 65535; + /** + * {@return the latest major Java version} + */ static int latestMajorVersion() { return JAVA_22_VERSION; } + /** + * {@return the latest minor Java version} + */ static int latestMinorVersion() { return 0; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/ClassfileBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/ClassfileBuilder.java index 241470e6d9c..965bfb293e7 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/ClassfileBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/ClassfileBuilder.java @@ -38,6 +38,8 @@ import jdk.internal.classfile.constantpool.ConstantPoolBuilder; * abstractly (by passing a {@link ClassfileElement} to {@link #with(ClassfileElement)} * or concretely by calling the various {@code withXxx} methods. * + * @param the element type + * @param the builder type * @see ClassfileTransform */ public sealed interface ClassfileBuilder> 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 or T} 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);