Skip to content

Commit d606a65

Browse files
authored
Merge pull request #19830 from theresa-m/acc_strict_format
Class verification and ddr support for value types ACC_STRICT
2 parents 1be5b98 + 5ccd1cc commit d606a65

File tree

8 files changed

+191
-15
lines changed

8 files changed

+191
-15
lines changed

debugtools/DDR_VM/src/com/ibm/j9ddr/vm29/tools/ddrinteractive/commands/J9BCUtil.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ public static void j9bcutil_dumpRomMethod(PrintStream out, J9ROMMethodPointer ro
234234
* -ACC_TRANSIENT
235235
* -ACC_SYNTHETIC
236236
* -ACC_ENUM
237+
* -ACC_STRICT
237238
* -J9FieldFlagConstant
238239
* -J9FieldFlagIsNullRestricted
239240
*
@@ -433,6 +434,11 @@ private static void dumpModifiers(PrintStream out, long modifiers, int modifierS
433434
out.append("transient ");
434435
modifiers &= ~J9CfrClassFile.CFR_ACC_TRANSIENT;
435436
}
437+
438+
if ((modifiers & J9CfrClassFile.CFR_ACC_STRICT) != 0) {
439+
out.append("strict ");
440+
modifiers &= ~J9CfrClassFile.CFR_ACC_STRICT;
441+
}
436442
}
437443

438444
if (modifiers != 0) {

runtime/bcutil/cfreader.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1717,6 +1717,24 @@ checkFields(J9PortLibrary* portLib, J9CfrClassFile * classfile, U_8 * segment, U
17171717
goto _errorFound;
17181718
}
17191719
}
1720+
1721+
/* Each field of a value class must have exactly one of its ACC_STATIC or ACC_STRICT flags set. */
1722+
if (J9_ARE_NO_BITS_SET(value, CFR_ACC_STRICT | CFR_ACC_STATIC)) {
1723+
errorCode = J9NLS_CFR_ERR_VALUE_CLASS_FIELD_NOT_STATIC_OR_STRICT__ID;
1724+
goto _errorFound;
1725+
}
1726+
}
1727+
1728+
/* A field must not have set both ACC_STRICT and ACC_STATIC. */
1729+
if (J9_ARE_ALL_BITS_SET(value, CFR_ACC_STRICT | CFR_ACC_STATIC)) {
1730+
errorCode = J9NLS_CFR_ERR_FIELD_CANT_BE_STRICT_AND_STATIC__ID;
1731+
goto _errorFound;
1732+
}
1733+
1734+
/* A field that has set ACC_STRICT must also have set ACC_FINAL. */
1735+
if (J9_ARE_ALL_BITS_SET(value, CFR_ACC_STRICT) && J9_ARE_NO_BITS_SET(value, CFR_ACC_FINAL)) {
1736+
errorCode = J9NLS_CFR_ERR_STRICT_FIELD_MUST_BE_FINAL__ID;
1737+
goto _errorFound;
17201738
}
17211739
#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */
17221740

runtime/bcverify/vrfyhelp.c

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ static IDATA findFieldFromRamClass (J9Class ** ramClass, J9ROMFieldRef * field,
4949
static IDATA findMethodFromRamClass (J9BytecodeVerificationData * verifyData, J9Class ** ramClass, J9ROMNameAndSignature * method, UDATA firstSearch);
5050
static VMINLINE UDATA * pushType (J9BytecodeVerificationData *verifyData, U_8 * signature, UDATA * stackTop);
5151
static IDATA isRAMClassCompatible(J9BytecodeVerificationData *verifyData, U_8* parentClass, UDATA parentLength, U_8* childClass, UDATA childLength, IDATA *reasonCode);
52-
static IDATA findFieldFromCurrentRomClass(J9ROMClass *romClass, J9ROMFieldRef *field);
52+
static J9ROMFieldShape *findFieldFromCurrentRomClass(J9ROMClass *romClass, J9ROMFieldRef *field);
5353

5454
J9_DECLARE_CONSTANT_UTF8(j9_vrfy_Object, "java/lang/Object");
5555
J9_DECLARE_CONSTANT_UTF8(j9_vrfy_String, "java/lang/String");
@@ -903,7 +903,18 @@ isFieldAccessCompatible(J9BytecodeVerificationData *verifyData, J9ROMFieldRef *f
903903
*reasonCode = 0;
904904

905905
if (JBputfield == bytecode) {
906+
J9BranchTargetStack *liveStack = (J9BranchTargetStack *)verifyData->liveStack;
907+
J9ROMFieldShape *field = findFieldFromCurrentRomClass(romClass, fieldRef);
908+
#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
909+
IDATA isStrictField = (NULL != field) && J9_ARE_ALL_BITS_SET(field->modifiers, J9AccStrict);
910+
#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
906911
if (J9_ARE_ALL_BITS_SET(receiver, BCV_SPECIAL_INIT)) {
912+
#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
913+
if (FALSE == liveStack->uninitializedThis && isStrictField) {
914+
/* ACC_STRICT field must be assigned before instance initialization method. */
915+
return (IDATA)FALSE;
916+
}
917+
#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
907918
J9UTF8 *classString = ((J9UTF8 *) J9ROMCLASS_CLASSNAME(romClass));
908919
if (utf8string != classString) {
909920
/* The following test is not necessary if the class name is uniquely referenced in a class */
@@ -931,10 +942,15 @@ isFieldAccessCompatible(J9BytecodeVerificationData *verifyData, J9ROMFieldRef *f
931942
* the field is accessible only when it exists in the subclass or the superclass's
932943
* initialization is completed in which case uninitializedThis is set to FALSE.
933944
*/
934-
J9BranchTargetStack *liveStack = (J9BranchTargetStack *)verifyData->liveStack;
935-
return findFieldFromCurrentRomClass(romClass, fieldRef) || !liveStack->uninitializedThis;
945+
return (NULL != field) || !liveStack->uninitializedThis;
936946
}
937947
}
948+
#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
949+
else if (isStrictField) {
950+
/* putfield is not allowed outside of initialization for strict fields. */
951+
return (IDATA)FALSE;
952+
}
953+
#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
938954
}
939955
return isClassCompatibleByName(verifyData, receiver, J9UTF8_DATA(utf8string), J9UTF8_LENGTH(utf8string), reasonCode);
940956
}
@@ -1222,10 +1238,10 @@ storeVerifyErrorData (J9BytecodeVerificationData * verifyData, I_16 errorDetailC
12221238
*
12231239
* @param romClass a pointer to J9ROMClass
12241240
* @param field a pointer to J9ROMFieldRef
1225-
* @return TRUE if it exists in the current ROM class
1226-
* FALSE when the field doesn't exist
1241+
* @return J9ROMFieldShape* if it exists in the current ROM class
1242+
* or NULL when the field doesn't exist
12271243
*/
1228-
static IDATA
1244+
static J9ROMFieldShape *
12291245
findFieldFromCurrentRomClass(J9ROMClass *romClass, J9ROMFieldRef *field)
12301246
{
12311247
J9UTF8 *searchName = J9ROMNAMEANDSIGNATURE_NAME(J9ROMFIELDREF_NAMEANDSIGNATURE(field));
@@ -1240,11 +1256,10 @@ findFieldFromCurrentRomClass(J9ROMClass *romClass, J9ROMFieldRef *field)
12401256
&& compareTwoUTF8s(searchName, J9ROMFIELDSHAPE_NAME(currentField))
12411257
&& compareTwoUTF8s(searchSignature, J9ROMFIELDSHAPE_SIGNATURE(currentField))
12421258
) {
1243-
isFieldFound = (IDATA)TRUE;
12441259
break;
12451260
}
12461261
currentField = romFieldsNextDo(&state);
12471262
}
12481263

1249-
return isFieldFound;
1264+
return currentField;
12501265
}

runtime/cfdumper/main.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,9 @@ static void printField(J9CfrClassFile* classfile, J9CfrField* field)
12981298
if(field->accessFlags & CFR_ACC_FINAL) j9tty_printf( PORTLIB, "final ");
12991299
if(field->accessFlags & CFR_ACC_VOLATILE) j9tty_printf( PORTLIB, "volatile ");
13001300
if(field->accessFlags & CFR_ACC_TRANSIENT) j9tty_printf( PORTLIB, "transient ");
1301+
#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
1302+
if(field->accessFlags & CFR_ACC_STRICT) j9tty_printf( PORTLIB, "strict ");
1303+
#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
13011304

13021305
/* Return type. */
13031306
string = classfile->constantPool[field->descriptorIndex].bytes;

runtime/nls/cfre/cfrerr.nls

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1788,3 +1788,24 @@ J9NLS_CFR_ERR_CLASS_MUST_HAVE_AT_LEAST_ONE_FINAL_IDENTITY_ABSTRACT_FLAG.explanat
17881788
J9NLS_CFR_ERR_CLASS_MUST_HAVE_AT_LEAST_ONE_FINAL_IDENTITY_ABSTRACT_FLAG.system_action=The JVM will throw a verification or classloading related exception such as java.lang.ClassFormatError.
17891789
J9NLS_CFR_ERR_CLASS_MUST_HAVE_AT_LEAST_ONE_FINAL_IDENTITY_ABSTRACT_FLAG.user_response=Contact the provider of the classfile for a corrected version.
17901790
# END NON-TRANSLATABLE
1791+
1792+
J9NLS_CFR_ERR_VALUE_CLASS_FIELD_NOT_STATIC_OR_STRICT=Value class fields must have either ACC_STATIC or ACC_STRICT set
1793+
# START NON-TRANSLATABLE
1794+
J9NLS_CFR_ERR_VALUE_CLASS_FIELD_NOT_STATIC_OR_STRICT.explanation=Please consult the Java Virtual Machine Specification for a detailed explanation.
1795+
J9NLS_CFR_ERR_VALUE_CLASS_FIELD_NOT_STATIC_OR_STRICT.system_action=The JVM will throw a verification or classloading related exception such as java.lang.ClassFormatError.
1796+
J9NLS_CFR_ERR_VALUE_CLASS_FIELD_NOT_STATIC_OR_STRICT.user_response=Contact the provider of the classfile for a corrected version.
1797+
# END NON-TRANSLATABLE
1798+
1799+
J9NLS_CFR_ERR_FIELD_CANT_BE_STRICT_AND_STATIC=A field must not have both ACC_STRICT and ACC_STATIC flags set
1800+
# START NON-TRANSLATABLE
1801+
J9NLS_CFR_ERR_FIELD_CANT_BE_STRICT_AND_STATIC.explanation=Please consult the Java Virtual Machine Specification for a detailed explanation.
1802+
J9NLS_CFR_ERR_FIELD_CANT_BE_STRICT_AND_STATIC.system_action=The JVM will throw a verification or classloading related exception such as java.lang.ClassFormatError.
1803+
J9NLS_CFR_ERR_FIELD_CANT_BE_STRICT_AND_STATIC.user_response=Contact the provider of the classfile for a corrected version.
1804+
# END NON-TRANSLATABLE
1805+
1806+
J9NLS_CFR_ERR_STRICT_FIELD_MUST_BE_FINAL=A field with ACC_STRICT set must also set ACC_FINAL
1807+
# START NON-TRANSLATABLE
1808+
J9NLS_CFR_ERR_STRICT_FIELD_MUST_BE_FINAL.explanation=Please consult the Java Virtual Machine Specification for a detailed explanation.
1809+
J9NLS_CFR_ERR_STRICT_FIELD_MUST_BE_FINAL.system_action=The JVM will throw a verification or classloading related exception such as java.lang.ClassFormatError.
1810+
J9NLS_CFR_ERR_STRICT_FIELD_MUST_BE_FINAL.user_response=Contact the provider of the classfile for a corrected version.
1811+
# END NON-TRANSLATABLE

runtime/oti/cfr.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -919,11 +919,12 @@ typedef struct J9CfrClassFile {
919919

920920
#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)
921921
#define CFR_CLASS_ACCESS_MASK (CFR_ACC_PUBLIC | CFR_ACC_FINAL | CFR_ACC_IDENTITY | CFR_ACC_INTERFACE | CFR_ACC_ABSTRACT | CFR_ACC_SYNTHETIC | CFR_ACC_ANNOTATION | CFR_ACC_ENUM)
922+
#define CFR_FIELD_ACCESS_MASK (CFR_ACC_PUBLIC | CFR_ACC_PRIVATE | CFR_ACC_PROTECTED | CFR_ACC_STATIC | CFR_ACC_FINAL | CFR_ACC_VOLATILE | CFR_ACC_TRANSIENT | CFR_ACC_SYNTHETIC | CFR_ACC_ENUM | CFR_ACC_STRICT)
922923
#else /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */
923924
#define CFR_CLASS_ACCESS_MASK (CFR_ACC_PUBLIC | CFR_ACC_FINAL | CFR_ACC_SUPER | CFR_ACC_INTERFACE | CFR_ACC_ABSTRACT | CFR_ACC_SYNTHETIC | CFR_ACC_ANNOTATION | CFR_ACC_ENUM)
925+
#define CFR_FIELD_ACCESS_MASK (CFR_ACC_PUBLIC | CFR_ACC_PRIVATE | CFR_ACC_PROTECTED | CFR_ACC_STATIC | CFR_ACC_FINAL | CFR_ACC_VOLATILE | CFR_ACC_TRANSIENT | CFR_ACC_SYNTHETIC | CFR_ACC_ENUM)
924926
#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */
925927
#define CFR_INTERFACE_CLASS_ACCESS_MASK (CFR_ACC_PUBLIC | CFR_ACC_INTERFACE | CFR_ACC_ABSTRACT | CFR_ACC_SYNTHETIC | CFR_ACC_ANNOTATION)
926-
#define CFR_FIELD_ACCESS_MASK (CFR_ACC_PUBLIC | CFR_ACC_PRIVATE | CFR_ACC_PROTECTED | CFR_ACC_STATIC | CFR_ACC_FINAL | CFR_ACC_VOLATILE | CFR_ACC_TRANSIENT | CFR_ACC_SYNTHETIC | CFR_ACC_ENUM)
927928
#define CFR_INTERFACE_FIELD_ACCESS_MASK (CFR_ACC_PUBLIC | CFR_ACC_STATIC | CFR_ACC_FINAL | CFR_ACC_SYNTHETIC)
928929
#define CFR_INTERFACE_FIELD_ACCESS_REQUIRED (CFR_ACC_PUBLIC | CFR_ACC_STATIC | CFR_ACC_FINAL)
929930
#define CFR_METHOD_ACCESS_MASK (CFR_ACC_PUBLIC | CFR_ACC_PRIVATE | CFR_ACC_PROTECTED | CFR_ACC_STATIC | CFR_ACC_FINAL | CFR_ACC_SYNCHRONIZED | CFR_ACC_BRIDGE | CFR_ACC_VARARGS | CFR_ACC_NATIVE | CFR_ACC_STRICT | CFR_ACC_ABSTRACT | CFR_ACC_SYNTHETIC)

test/functional/Valhalla/src_qtypes/org/openj9/test/lworld/ValueTypeGenerator.java

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ private static class ClassConfiguration {
5151
private boolean isReference;
5252
private boolean hasNonStaticSynchronizedMethods;
5353
private int extraClassFlags;
54+
private boolean generateIllegalSetters;
5455

5556
/**
5657
* @see setAccessedContainer
@@ -178,6 +179,14 @@ public void setValueClassUsedInCode(ClassConfiguration valueClassUsedInCode) {
178179
public ClassConfiguration getValueClassUsedInCode() {
179180
return valueClassUsedInCode;
180181
}
182+
183+
public void setGenerateIllegalSetters() {
184+
generateIllegalSetters = true;
185+
}
186+
187+
public boolean getGenerateIllegalSetters() {
188+
return generateIllegalSetters;
189+
}
181190
}
182191

183192
private static byte[] generateClass(ClassConfiguration config) {
@@ -199,6 +208,7 @@ private static byte[] generateClass(ClassConfiguration config) {
199208
boolean isVerifiable = config.isVerifiable();
200209
boolean isRef = config.isReference();
201210
boolean addSyncMethods = config.hasNonStaticSynchronizedMethods();
211+
boolean generateIllegalSetters = config.getGenerateIllegalSetters();
202212

203213
ClassWriter cw = new ClassWriter(0);
204214
FieldVisitor fv;
@@ -237,9 +247,9 @@ private static byte[] generateClass(ClassConfiguration config) {
237247
if ((nameAndSigValue.length > 2) && nameAndSigValue[2].equals("static")) {
238248
fieldModifiers = ACC_PUBLIC + ACC_STATIC;
239249
} else if ((nameAndSigValue.length > 3) && nameAndSigValue[3].equals("volatile")) {
240-
fieldModifiers = ACC_PUBLIC + ACC_FINAL + ACC_VOLATILE;
250+
fieldModifiers = ACC_PUBLIC + ACC_FINAL + ACC_STRICT + ACC_VOLATILE;
241251
} else {
242-
fieldModifiers = ACC_PUBLIC + ACC_FINAL;
252+
fieldModifiers = ACC_PUBLIC + ACC_FINAL + ACC_STRICT;
243253
}
244254
}
245255
fv = cw.visitField(fieldModifiers, nameAndSigValue[0], nameAndSigValue[1], null, null);
@@ -257,7 +267,7 @@ private static byte[] generateClass(ClassConfiguration config) {
257267
}
258268
}
259269

260-
generateFieldMethods(cw, nameAndSigValue, className, isVerifiable, isRef);
270+
generateFieldMethods(cw, nameAndSigValue, className, isVerifiable, isRef, generateIllegalSetters);
261271
}
262272

263273
addInit(cw);
@@ -317,7 +327,7 @@ private static void addSynchronizedMethods(ClassWriter cw) {
317327
mv.visitEnd();
318328
}
319329

320-
private static void generateFieldMethods(ClassWriter cw, String[] nameAndSigValue, String className, boolean isVerifiable, boolean isRef) {
330+
private static void generateFieldMethods(ClassWriter cw, String[] nameAndSigValue, String className, boolean isVerifiable, boolean isRef, boolean generateIllegalSetters) {
321331
if ((nameAndSigValue.length > 2) && nameAndSigValue[2].equals("static")) {
322332
generateSetterStatic(cw, nameAndSigValue, className);
323333
generateGetterStatic(cw, nameAndSigValue, className);
@@ -327,10 +337,14 @@ private static void generateFieldMethods(ClassWriter cw, String[] nameAndSigValu
327337
}
328338
} else {
329339
generateGetter(cw, nameAndSigValue, className);
330-
generateSetter(cw, nameAndSigValue, className);
340+
if (isRef || generateIllegalSetters) {
341+
generateSetter(cw, nameAndSigValue, className);
342+
}
331343
if (!isVerifiable) {
332344
generateGetterGeneric(cw, nameAndSigValue, className);
333-
generateSetterGeneric(cw, nameAndSigValue, className);
345+
if (isRef || generateIllegalSetters) {
346+
generateSetterGeneric(cw, nameAndSigValue, className);
347+
}
334348
}
335349
}
336350
}
@@ -1120,4 +1134,63 @@ public static void generateNonInterfaceClassWithMissingFlags(String name) {
11201134
byte[] bytes = classWriter.toByteArray();
11211135
generator.defineClass(name, bytes, 0, bytes.length);
11221136
}
1137+
1138+
public static void generateTestFieldCantHaveAccFinalAndAccVolatile() {
1139+
generateAccStaticTestGeneric("TestFieldCantHaveAccFinalAndAccVolatile", ACC_FINAL | ACC_VOLATILE, true);
1140+
}
1141+
1142+
public static void generateTestFieldCantHaveAccStrictAndAccStatic() {
1143+
generateAccStaticTestGeneric("TestFieldCantHaveAccStrictAndAccStatic", ACC_STRICT | ACC_STATIC, true);
1144+
}
1145+
1146+
public static void generateTestAccStrictFieldMustHaveAccFinal() {
1147+
generateAccStaticTestGeneric("TestAccStrictFieldMustHaveAccFinal", ACC_STRICT, true);
1148+
}
1149+
1150+
public static void generateTestValueClassFieldMustHaveAccStaticOrAccStrict() {
1151+
generateAccStaticTestGeneric("TestValueClassFieldMustHaveAccStaticOrAccStrict", 0, false);
1152+
}
1153+
1154+
public static Class<?> generateTestValueClassPutStrictFieldAfterInitialization() {
1155+
return generateAccStaticTestGeneric("TestValueClassPutStrictFieldAfterInitialization", ACC_FINAL | ACC_STRICT, false, true);
1156+
}
1157+
1158+
private static Class<?> generateAccStaticTestGeneric(String name, int fieldFlags, boolean isRef) {
1159+
return generateAccStaticTestGeneric(name, fieldFlags, isRef, false);
1160+
}
1161+
1162+
private static Class<?> generateAccStaticTestGeneric(String className, int fieldFlags, boolean isRef, boolean genIllegalInit) {
1163+
String fieldName = "o";
1164+
String fieldDesc = "LObject;";
1165+
1166+
ClassWriter classWriter = new ClassWriter(0);
1167+
classWriter.visit(ValhallaUtils.VALUE_TYPE_CLASS_FILE_VERSION,
1168+
ACC_PUBLIC + ACC_FINAL + (isRef ? ValhallaUtils.ACC_IDENTITY : 0),
1169+
className, null, "java/lang/Object", null);
1170+
classWriter.visitField(fieldFlags, fieldName, fieldDesc, null, null);
1171+
1172+
if (genIllegalInit) {
1173+
MethodVisitor mv = classWriter.visitMethod(ACC_PUBLIC, "<init>", "(" + fieldDesc + ")V", null, null);
1174+
mv.visitCode();
1175+
mv.visitVarInsn(ALOAD, 0);
1176+
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
1177+
mv.visitVarInsn(ALOAD, 0);
1178+
mv.visitVarInsn(ALOAD, 1);
1179+
mv.visitFieldInsn(PUTFIELD, className, fieldName, fieldDesc);
1180+
mv.visitInsn(RETURN);
1181+
mv.visitMaxs(2, 2);
1182+
mv.visitEnd();
1183+
}
1184+
1185+
classWriter.visitEnd();
1186+
byte[] bytes = classWriter.toByteArray();
1187+
return generator.defineClass(className, bytes, 0, bytes.length);
1188+
}
1189+
1190+
public static Class<?> generateValueClassWithIllegalSetters(String name, String[] fields) {
1191+
ClassConfiguration classConfig = new ClassConfiguration(name, fields);
1192+
classConfig.setGenerateIllegalSetters();
1193+
byte[] bytes = generateClass(classConfig);
1194+
return generator.defineClass(name, bytes, 0, bytes.length);
1195+
}
11231196
}

test/functional/Valhalla/src_qtypes/org/openj9/test/lworld/ValueTypeTests.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2889,6 +2889,45 @@ static public void testNonInterfaceClassMustHaveFinalIdentityAbstractSet() throw
28892889
ValueTypeGenerator.generateNonInterfaceClassWithMissingFlags("testNonInterfaceClassMustHaveFinalIdentityAbstractSet");
28902890
}
28912891

2892+
/* A field must not have set both ACC_FINAL and ACC_VOLATILE */
2893+
@Test(expectedExceptions = java.lang.ClassFormatError.class, expectedExceptionsMessageRegExp = ".*field cannot be both final and volatile.*")
2894+
static public void testFieldCantHaveAccFinalAndAccVolatile() {
2895+
ValueTypeGenerator.generateTestFieldCantHaveAccFinalAndAccVolatile();
2896+
}
2897+
2898+
/* A field must not have set both ACC_STRICT and ACC_STATIC */
2899+
@Test(expectedExceptions = java.lang.ClassFormatError.class, expectedExceptionsMessageRegExp = ".*A field must not have both ACC_STRICT and ACC_STATIC flags set.*")
2900+
static public void testFieldCantHaveAccStrictAndAccStatic() {
2901+
ValueTypeGenerator.generateTestFieldCantHaveAccStrictAndAccStatic();
2902+
}
2903+
2904+
/* A field that has set ACC_STRICT must also have set ACC_FINAL */
2905+
@Test(expectedExceptions = java.lang.ClassFormatError.class, expectedExceptionsMessageRegExp = ".*A field with ACC_STRICT set must also set ACC_FINAL.*")
2906+
static public void testAccStrictFieldMustHaveAccFinal() {
2907+
ValueTypeGenerator.generateTestAccStrictFieldMustHaveAccFinal();
2908+
}
2909+
2910+
/* Each field of a value class must have exactly one of its ACC_STATIC or ACC_STRICT flags set */
2911+
@Test(expectedExceptions = java.lang.ClassFormatError.class, expectedExceptionsMessageRegExp = ".*Fields of value classes must have either ACC_STATIC or ACC_FINAL flags set.*")
2912+
static public void testValueClassFieldMustHaveAccStaticOrAccStrict() {
2913+
ValueTypeGenerator.generateTestValueClassFieldMustHaveAccStaticOrAccStrict();
2914+
}
2915+
2916+
/* putfield is not allowed outside <init> for ACC_STRICT fields */
2917+
@Test(expectedExceptions = VerifyError.class)
2918+
static public void testValueClassWithIllegalSetters() throws Throwable {
2919+
String fields[] = {"x:I"};
2920+
Class valueClass = ValueTypeGenerator.generateValueClassWithIllegalSetters("TestValueClassWithIllegalSetters", fields);
2921+
valueClass.newInstance();
2922+
}
2923+
2924+
/* putfield not allowed in <init> after class initialization for ACC_STRICT fields */
2925+
@Test(expectedExceptions = VerifyError.class)
2926+
static public void testValueClassPutStrictFieldAfterInitialization() throws Throwable {
2927+
Class valueClass = ValueTypeGenerator.generateTestValueClassPutStrictFieldAfterInitialization();
2928+
valueClass.newInstance();
2929+
}
2930+
28922931
static MethodHandle generateGetter(Class<?> clazz, String fieldName, Class<?> fieldType) {
28932932
try {
28942933
return lookup.findVirtual(clazz, "get"+fieldName, MethodType.methodType(fieldType));

0 commit comments

Comments
 (0)