Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 48 additions & 1 deletion runtime/bcverify/bcverify.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ static IDATA simulateStack (J9BytecodeVerificationData * verifyData);
static IDATA parseOptions (J9JavaVM *vm, char *optionValues, const char **errorString);
static IDATA setVerifyState ( J9JavaVM *vm, char *option, const char **errorString );

#if defined(J9VM_OPT_VALHALLA_STRICT_FIELDS)
static UDATA strictFieldHashFn(void *key, void *userData);
static UDATA strictFieldHashEqualFn(void *leftKey, void *rightKey, void *userData);
#endif /* defined(J9VM_OPT_VALHALLA_STRICT_FIELDS) */

/**
* Walk the J9-format stack maps and set the uninitialized_this flag appropriately
Expand Down Expand Up @@ -2302,9 +2306,12 @@ j9bcv_freeVerificationData (J9PortLibrary * portLib, J9BytecodeVerificationData
{
PORT_ACCESS_FROM_PORT(portLib);
if (verifyData) {
#if defined(J9VM_OPT_VALHALLA_STRICT_FIELDS)
hashTableFree(verifyData->strictFields);
#endif /* defined(J9VM_OPT_VALHALLA_STRICT_FIELDS) */
#ifdef J9VM_THR_PREEMPTIVE
JavaVM* jniVM = (JavaVM*)verifyData->javaVM;
J9ThreadEnv* threadEnv;
J9ThreadEnv* threadEnv;
(*jniVM)->GetEnv(jniVM, (void**)&threadEnv, J9THREAD_VERSION_1_1);

threadEnv->monitor_destroy( verifyData->verifierMutex );
Expand Down Expand Up @@ -2344,6 +2351,22 @@ j9bcv_initializeVerificationData(J9JavaVM* javaVM)
goto error_no_memory;
}
#endif
#if defined(J9VM_OPT_VALHALLA_STRICT_FIELDS)
verifyData->strictFieldsUnsetCount = 0;
verifyData->strictFields = hashTableNew(
OMRPORT_FROM_J9PORT(PORTLIB),
J9_GET_CALLSITE(),
0,
sizeof(J9StrictFieldEntry),
0, 0,
J9MEM_CATEGORY_CLASSES,
strictFieldHashFn,
strictFieldHashEqualFn,
NULL, javaVM);
if (NULL == verifyData->strictFields) {
goto error_no_memory;
}
#endif /* defined(J9VM_OPT_VALHALLA_STRICT_FIELDS) */

verifyData->verifyBytecodesFunction = j9bcv_verifyBytecodes;
verifyData->checkClassLoadingConstraintForNameFunction = j9bcv_checkClassLoadingConstraintForName;
Expand Down Expand Up @@ -2417,6 +2440,9 @@ j9bcv_verifyBytecodes (J9PortLibrary * portLib, J9Class * clazz, J9ROMClass * ro
BOOLEAN classVersionRequiresStackmaps = romClass->majorVersion >= CFR_MAJOR_VERSION_REQUIRING_STACKMAPS;
BOOLEAN newFormat = (classVersionRequiresStackmaps || hasStackMaps);
BOOLEAN verboseVerification = (J9_VERIFY_VERBOSE_VERIFICATION == (verifyData->verificationFlags & J9_VERIFY_VERBOSE_VERIFICATION));
#if defined(J9VM_OPT_VALHALLA_STRICT_FIELDS)
BOOLEAN initMethodFound = TRUE;
#endif /* defined(J9VM_OPT_VALHALLA_STRICT_FIELDS) */

PORT_ACCESS_FROM_PORT(portLib);

Expand Down Expand Up @@ -2581,6 +2607,13 @@ j9bcv_verifyBytecodes (J9PortLibrary * portLib, J9Class * clazz, J9ROMClass * ro
ALWAYS_TRIGGER_J9HOOK_VM_METHOD_VERIFICATION_START(verifyData->javaVM->hookInterface, verifyData);
}

#if defined(J9VM_OPT_VALHALLA_STRICT_FIELDS)
/* TODO Update the class version check if strict fields is released before value types. */
if (J9_IS_CLASSFILE_OR_ROMCLASS_VALUETYPE_VERSION(romClass) && isInitMethod) {
createOrResetStrictFieldsList(verifyData, &initMethodFound);
}
#endif /* defined(J9VM_OPT_VALHALLA_STRICT_FIELDS) */

result = j9rtv_verifyBytecodes (verifyData);

if (BCV_ERR_INSUFFICIENT_MEMORY == result) {
Expand Down Expand Up @@ -2869,4 +2902,18 @@ bcvHookClassesUnload(J9HookInterface** hook, UDATA eventNum, void* eventData, vo
}
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */

#if defined(J9VM_OPT_VALHALLA_STRICT_FIELDS)
static UDATA strictFieldHashFn(void *key, void *userData) {
J9StrictFieldEntry *entry = key;
J9JavaVM *vm = userData;
return J9_VM_FUNCTION_VIA_JAVAVM(vm, computeHashForUTF8)(entry->name, entry->nameLength);
}

static UDATA strictFieldHashEqualFn(void *leftKey, void *rightKey, void *userData) {
J9StrictFieldEntry *leftEntry = leftKey;
J9StrictFieldEntry *rightEntry = rightKey;
return J9UTF8_DATA_EQUALS(leftEntry->name, leftEntry->nameLength, rightEntry->name, rightEntry->nameLength);
}
#endif /* defined(J9VM_OPT_VALHALLA_STRICT_FIELDS) */


29 changes: 27 additions & 2 deletions runtime/bcverify/rtverify.c
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,9 @@ verifyBytecodes (J9BytecodeVerificationData * verifyData)
UDATA errorStackIndex = (UDATA)-1;
UDATA errorTempData = (UDATA)-1;
BOOLEAN isNextStack = FALSE;
#if defined(J9VM_OPT_VALHALLA_STRICT_FIELDS)
BOOLEAN anotherInstanceInitCalled = FALSE;
#endif /* defined(J9VM_OPT_VALHALLA_STRICT_FIELDS) */

Trc_RTV_verifyBytecodes_Entry(verifyData->vmStruct,
(UDATA) J9UTF8_LENGTH(J9ROMMETHOD_NAME(romMethod)),
Expand Down Expand Up @@ -1457,7 +1460,11 @@ verifyBytecodes (J9BytecodeVerificationData * verifyData)
stackTop = pushFieldType(verifyData, utf8string, stackTop);
}

rc = isFieldAccessCompatible (verifyData, (J9ROMFieldRef *) info, bc, receiver, &reasonCode);
rc = isFieldAccessCompatible (verifyData, (J9ROMFieldRef *) info, bc, receiver, &reasonCode
#if defined(J9VM_OPT_VALHALLA_STRICT_FIELDS)
, isInitMethod, anotherInstanceInitCalled
#endif /* defined(J9VM_OPT_VALHALLA_STRICT_FIELDS) */
);
if (BCV_ERR_INSUFFICIENT_MEMORY == reasonCode) {
goto _outOfMemoryError;
}
Expand Down Expand Up @@ -1676,8 +1683,8 @@ verifyBytecodes (J9BytecodeVerificationData * verifyData)
}
}

/* Ensure the <init> method is either for this class or its direct super class */
if (type & BCV_SPECIAL_INIT) {
/* Ensure the <init> method is either for this class or its direct super class. */
UDATA superClassIndex = 0;

utf8string = J9ROMSTRINGREF_UTF8DATA(classRef);
Expand All @@ -1695,6 +1702,24 @@ verifyBytecodes (J9BytecodeVerificationData * verifyData)
errorStackIndex = stackTop - liveStack->stackElements;
goto _inconsistentStack2;
}

#if defined(J9VM_OPT_VALHALLA_STRICT_FIELDS)
/* TODO Update the class version check if strict fields is released before value types. */
if (J9_IS_CLASSFILE_OR_ROMCLASS_VALUETYPE_VERSION(verifyData->romClass)) {
if (classIndex == superClassIndex) {
/* All strict instance fields must be assigned before
* invoking the <init> method of a superclass.
*/
if (verifyData->strictFieldsUnsetCount > 0) {
errorType = J9NLS_BCV_ERR_BAD_INVOKESPECIAL__ID;
verboseErrorCode = BCV_ERR_BAD_INVOKESPECIAL;
goto _miscError;
}
} else {
anotherInstanceInitCalled = TRUE;
}
}
#endif /* defined(J9VM_OPT_VALHALLA_STRICT_FIELDS) */
}

/* This invoke special will make all copies of this "type" on the stack a real
Expand Down
91 changes: 82 additions & 9 deletions runtime/bcverify/vrfyhelp.c
Original file line number Diff line number Diff line change
Expand Up @@ -888,14 +888,27 @@ j9bcv_createVerifyErrorString(J9PortLibrary * portLib, J9BytecodeVerificationDat
/*
* Validates field access compatibility
*
* Update strictFields map for putfield
* bytecode of strict final fields.
*
* returns TRUE if class are compatible
* returns FALSE it not compatible
* reasonCode (set by isClassCompatibleByName) is:
* BCV_ERR_INSUFFICIENT_MEMORY :in OOM error case
*/
IDATA
isFieldAccessCompatible(J9BytecodeVerificationData *verifyData, J9ROMFieldRef *fieldRef, UDATA bytecode, UDATA receiver, IDATA *reasonCode)
{
isFieldAccessCompatible(
J9BytecodeVerificationData *verifyData,
J9ROMFieldRef *fieldRef,
UDATA bytecode,
UDATA receiver,
IDATA *reasonCode
#if defined(J9VM_OPT_VALHALLA_STRICT_FIELDS)
,
BOOLEAN isInitMethod,
BOOLEAN anotherInstanceInitCalled
#endif /* defined(J9VM_OPT_VALHALLA_STRICT_FIELDS) */
) {
J9ROMClass *romClass = verifyData->romClass;
J9ROMConstantPoolItem *constantPool = (J9ROMConstantPoolItem *)(romClass + 1);
J9UTF8 *utf8string = J9ROMCLASSREF_NAME((J9ROMClassRef *)&constantPool[fieldRef->classRefCPIndex]);
Expand All @@ -907,14 +920,31 @@ isFieldAccessCompatible(J9BytecodeVerificationData *verifyData, J9ROMFieldRef *f
J9ROMFieldShape *field = findFieldFromCurrentRomClass(romClass, fieldRef);

#if defined(J9VM_OPT_VALHALLA_STRICT_FIELDS)
/* A field declared by the current class with ACC_FINAL and ACC_STRICT flags
* can't be set unless the initialization state is early larval.
*/
if ((NULL != field)
&& J9ROMFIELD_IS_STRICT_FINAL(romClass, field->modifiers)
&& (FALSE == liveStack->uninitializedThis)
/* TODO Update the class version check if strict fields is released before value types. */
if (J9_IS_CLASSFILE_OR_ROMCLASS_VALUETYPE_VERSION(verifyData->romClass)
&& (NULL != field) && J9ROMFIELD_IS_STRICT(field->modifiers)
) {
return (IDATA)FALSE;
/* A strict final field cannot be set in the following cases:
* - the initialization state is not early larval
* - another instance initialization method has been called
*/
if (J9_ARE_ALL_BITS_SET(field->modifiers, J9AccFinal)
&& ((FALSE == liveStack->uninitializedThis) || (TRUE == anotherInstanceInitCalled))
) {
return (IDATA)FALSE;
}

if (isInitMethod && (TRUE == liveStack->uninitializedThis)) {
J9UTF8 *fieldName = J9ROMNAMEANDSIGNATURE_NAME(J9ROMFIELDREF_NAMEANDSIGNATURE(fieldRef));
J9StrictFieldEntry query = {0};
query.name = J9UTF8_DATA(fieldName);
query.nameLength = J9UTF8_LENGTH(fieldName);
J9StrictFieldEntry *entry = hashTableFind(verifyData->strictFields, &query);
if ((NULL != entry) && (FALSE == entry->isSet)) {
entry->isSet = TRUE;
verifyData->strictFieldsUnsetCount--;
}
}
}
#endif /* defined(J9VM_OPT_VALHALLA_STRICT_FIELDS) */

Expand Down Expand Up @@ -1259,3 +1289,46 @@ findFieldFromCurrentRomClass(J9ROMClass *romClass, J9ROMFieldRef *field)

return currentField;
}
#if defined(J9VM_OPT_VALHALLA_STRICT_FIELDS)

void
createOrResetStrictFieldsList(J9BytecodeVerificationData *verifyData, BOOLEAN *initMethodFound) {
if (*initMethodFound) {
*initMethodFound = FALSE;

/* Clear map entries from the last class. */
J9HashTableState hashTableState = {0};
J9StrictFieldEntry *entry = (J9StrictFieldEntry *)hashTableStartDo(verifyData->strictFields, &hashTableState);
while (NULL != entry) {
hashTableDoRemove(&hashTableState);
entry = hashTableNextDo(&hashTableState);
}

/* Create strictFields map of all strict instance fields. */
J9ROMFieldWalkState fieldWalkState = {0};
J9ROMFieldShape *field = romFieldsStartDo(verifyData->romClass, &fieldWalkState);
while (NULL != field) {
if (J9ROMFIELD_IS_STRICT(field->modifiers) && J9_ARE_NO_BITS_SET(field->modifiers, J9AccStatic)) {
J9UTF8 *fieldName = J9ROMFIELDSHAPE_NAME(field);
J9StrictFieldEntry newEntry = {0};
newEntry.name = J9UTF8_DATA(fieldName);
newEntry.nameLength = J9UTF8_LENGTH(fieldName);
newEntry.isSet = FALSE;
hashTableAdd(verifyData->strictFields, &newEntry);
}
field = romFieldsNextDo(&fieldWalkState);
}
} else {
/* Reset strictFields map and counter to be reused by another <init> method
* by marking all isSet flags as false.
*/
J9HashTableState hashTableState = {0};
J9StrictFieldEntry *entry = (J9StrictFieldEntry *)hashTableStartDo(verifyData->strictFields, &hashTableState);
while (NULL != entry) {
entry->isSet = FALSE;
entry = hashTableNextDo(&hashTableState);
}
}
verifyData->strictFieldsUnsetCount = hashTableGetCount(verifyData->strictFields);
}
#endif /* defined(J9VM_OPT_VALHALLA_STRICT_FIELDS) */
8 changes: 8 additions & 0 deletions runtime/oti/bcverify.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ typedef struct J9BranchTargetStack {
UDATA stackElements[1];
} J9BranchTargetStack;

#if defined(J9VM_OPT_VALHALLA_STRICT_FIELDS)
typedef struct J9StrictFieldEntry {
U_8 *name;
UDATA nameLength;
BOOLEAN isSet; /* isSet is not used for a query. */
} J9StrictFieldEntry;
#endif /* defined(J9VM_OPT_VALHALLA_STRICT_FIELDS) */

#define BCV_TARGET_STACK_HEADER_UDATA_SIZE 4
#define BCV_STACK_OVERFLOW_BUFFER_UDATA_SIZE 2

Expand Down
32 changes: 31 additions & 1 deletion runtime/oti/bcverify_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -414,10 +414,26 @@ isClassCompatibleByName(J9BytecodeVerificationData *verifyData, UDATA sourceClas
* @param receiver
* @param reasonCode
* output parameter denoting error conditions
* @param isInitMethod
* true if the current method is <init>
* @param anotherInstanceInitCalled
* true if the current method is <init> and another
* instance <init> has been called in this method
* @return IDATA
*/
IDATA
isFieldAccessCompatible(J9BytecodeVerificationData * verifyData, J9ROMFieldRef * fieldRef, UDATA bytecode, UDATA receiver, IDATA *reasonCode);
isFieldAccessCompatible(
J9BytecodeVerificationData *verifyData,
J9ROMFieldRef *fieldRef,
UDATA bytecode,
UDATA receiver,
IDATA *reasonCode
#if defined(J9VM_OPT_VALHALLA_STRICT_FIELDS)
,
BOOLEAN isInitMethod,
BOOLEAN anotherInstanceInitCalled
#endif /* defined(J9VM_OPT_VALHALLA_STRICT_FIELDS) */
);

/**
* @brief
Expand Down Expand Up @@ -494,6 +510,20 @@ pushLdcType(J9BytecodeVerificationData *verifyData, J9ROMClass * romClass, UDATA
UDATA*
pushReturnType(J9BytecodeVerificationData *verifyData, J9UTF8 * utf8string, UDATA * stackTop);

#if defined(J9VM_OPT_VALHALLA_STRICT_FIELDS)
/**
* Create or reset the list of strict instance fields for the class being
* verified. This list is used to track which strict fields have been
* set during the early larval state.
*
* @param verifyData information about the class being verified.
* @param initMethodFound true if this is the first <init> found in the class, false otherwise.
* @return void
*/
void
createOrResetStrictFieldsList(J9BytecodeVerificationData *verifyData, BOOLEAN *initMethodFound);
#endif /* defined(J9VM_OPT_VALHALLA_STRICT_FIELDS) */

/**
* Classification of Unicode characters for use in Java identifiers.
*/
Expand Down
5 changes: 1 addition & 4 deletions runtime/oti/j9.h
Original file line number Diff line number Diff line change
Expand Up @@ -373,10 +373,7 @@ static const struct { \
#define IS_CLASS_SIGNATURE(firstChar) ('L' == (firstChar))

#if defined(J9VM_OPT_VALHALLA_STRICT_FIELDS)
/* TODO Update the class version check if strict fields is released before value types. */
#define J9ROMFIELD_IS_STRICT_FINAL(romClassOrClassfile, fieldModifiers) \
(J9_IS_CLASSFILE_OR_ROMCLASS_VALUETYPE_VERSION(romClassOrClassfile) \
&& J9_ARE_ALL_BITS_SET(fieldModifiers, J9AccStrictInit | J9AccFinal))
#define J9ROMFIELD_IS_STRICT(fieldModifiers) J9_ARE_ALL_BITS_SET(fieldModifiers, J9AccStrictInit)
#endif /* defined(J9VM_OPT_VALHALLA_STRICT_FIELDS) */

#if defined(J9VM_OPT_CRIU_SUPPORT)
Expand Down
4 changes: 4 additions & 0 deletions runtime/oti/j9nonbuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -2187,6 +2187,10 @@ typedef struct J9BytecodeVerificationData {
struct J9PortLibrary * portLib;
struct J9JavaVM* javaVM;
BOOLEAN createdStackMap;
#if defined(J9VM_OPT_VALHALLA_STRICT_FIELDS)
J9HashTable *strictFields;
UDATA strictFieldsUnsetCount;
#endif /* defined(J9VM_OPT_VALHALLA_STRICT_FIELDS) */
} J9BytecodeVerificationData;

typedef struct J9BytecodeOffset {
Expand Down
Loading