Path: blob/master/runtime/bcutil/defineclass.c
5985 views
/*******************************************************************************1* Copyright (c) 1991, 2022 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include <stdlib.h>23#include <string.h>2425#include "j9.h"26#include "j9port.h"27#include "j9protos.h"28#include "j9consts.h"29#include "ut_j9bcu.h"30#include "objhelp.h"31#include "j2sever.h"32#include "bcutil_api.h"33#include "bcutil_internal.h"34#include "SCQueryFunctions.h"35#include "j9jclnls.h"3637#if defined(J9VM_OPT_DYNAMIC_LOAD_SUPPORT) /* File Level Build Flags */3839static UDATA classCouldPossiblyBeShared(J9VMThread * vmThread, J9LoadROMClassData * loadData);40static J9ROMClass * createROMClassFromClassFile (J9VMThread *currentThread, J9LoadROMClassData * loadData, J9TranslationLocalBuffer *localBuffer);41static void throwNoClassDefFoundError (J9VMThread* vmThread, J9LoadROMClassData * loadData);42static void reportROMClassLoadEvents (J9VMThread* vmThread, J9ROMClass* romClass, J9ClassLoader* classLoader);43static J9Class* checkForExistingClass (J9VMThread* vmThread, J9LoadROMClassData * loadData);44static UDATA callDynamicLoader(J9VMThread* vmThread, J9LoadROMClassData *loadData, U_8 * intermediateClassData, UDATA intermediateClassDataLength, UDATA translationFlags, UDATA classFileBytesReplacedByRIA, UDATA classFileBytesReplacedByRCA, J9TranslationLocalBuffer *localBuffer);4546static BOOLEAN hasSamePackageName(J9ROMClass *anonROMClass, J9ROMClass *hostROMClass);47static char* createErrorMessage(J9VMThread *vmStruct, J9ROMClass *anonROMClass, J9ROMClass *hostROMClass, const char* errorMsg);48static void setIllegalArgumentExceptionHostClassAnonClassHaveDifferentPackages(J9VMThread *vmStruct, J9ROMClass *anonROMClass, J9ROMClass *hostROMClass);49static void freeAnonROMClass(J9JavaVM *vm, J9ROMClass *romClass);5051#define GET_CLASS_LOADER_FROM_ID(vm, classLoader) ((classLoader) != NULL ? (classLoader) : (vm)->systemClassLoader)5253/*54* Warning: sender must hold class table mutex before calling.55*/56J9Class*57internalDefineClass(58J9VMThread* vmThread,59void* className,60UDATA classNameLength,61U_8* classData,62UDATA classDataLength,63j9object_t classDataObject,64J9ClassLoader* classLoader,65j9object_t protectionDomain,66UDATA options,67J9ROMClass *existingROMClass,68J9Class *hostClass,69J9TranslationLocalBuffer *localBuffer)70{71J9JavaVM* vm = vmThread->javaVM;72J9ROMClass* orphanROMClass = NULL;73J9ROMClass* romClass = NULL;74J9Class* result = NULL;75J9LoadROMClassData loadData = {0};76BOOLEAN isAnonFlagSet = J9_ARE_ALL_BITS_SET(options, J9_FINDCLASS_FLAG_ANON);77BOOLEAN isHiddenFlagSet = J9_ARE_ALL_BITS_SET(options, J9_FINDCLASS_FLAG_HIDDEN);7879/* This trace point is obsolete. It is retained only because j9vm test depends on it.80* Once j9vm tests are fixed, it would be marked as Obsolete in j9bcu.tdf81*/82Trc_BCU_internalDefineClass_Entry(vmThread, className, classNameLength, className);8384Trc_BCU_internalDefineClass_Entry1(vmThread, className, classNameLength, className, existingROMClass);85Trc_BCU_internalDefineClass_FullData(vmThread, classDataLength, classData, classLoader);8687classLoader = GET_CLASS_LOADER_FROM_ID(vm, classLoader);8889/* remember the current classpath entry so we can record it at the end */90vmThread->privateFlags &= ~J9_PRIVATE_FLAGS_CLOAD_NO_MEM;9192loadData.classBeingRedefined = NULL;93loadData.className = className;94loadData.classNameLength = classNameLength;95loadData.classData = classData;96loadData.classDataLength = classDataLength;97loadData.classDataObject = classDataObject;9899loadData.classLoader = classLoader;100if (isAnonFlagSet) {101loadData.classLoader = vm->anonClassLoader;102}103loadData.protectionDomain = protectionDomain;104loadData.options = options;105loadData.freeUserData = NULL;106loadData.freeFunction = NULL;107loadData.romClass = existingROMClass;108109loadData.hostPackageName = NULL;110loadData.hostPackageLength = 0;111if (isAnonFlagSet && (J2SE_VERSION(vm) >= J2SE_V11)) {112J9ROMClass *hostROMClass = hostClass->romClass;113loadData.hostPackageName = J9UTF8_DATA(J9ROMCLASS_CLASSNAME(hostROMClass));114loadData.hostPackageLength = packageNameLength(hostROMClass);115}116117if (J9_ARE_NO_BITS_SET(options, J9_FINDCLASS_FLAG_NO_CHECK_FOR_EXISTING_CLASS)) {118/* For non-bootstrap classes, this check is done in jcldefine.c:defineClassCommon(). */119if (checkForExistingClass(vmThread, &loadData) != NULL) {120Trc_BCU_internalDefineClass_Exit(vmThread, className, NULL);121return NULL;122}123}124125if (!isAnonFlagSet && !isHiddenFlagSet) {126/* See if there's already an orphan romClass available - still own classTableMutex at this point */127if (NULL != classLoader->romClassOrphansHashTable) {128orphanROMClass = romClassHashTableFind(classLoader->romClassOrphansHashTable, className, classNameLength);129if (NULL != orphanROMClass) {130loadData.romClass = orphanROMClass;131/* If enableBCI is specified, class was loaded from shared cache and previous attempt to create RAMClass failed,132* we can use the orphanROMClass created in previous attempt.133*/134if (0 != (loadData.options & J9_FINDCLASS_FLAG_SHRC_ROMCLASS_EXISTS)) {135Trc_BCU_Assert_NotEquals(NULL, vm->sharedClassConfig);136Trc_BCU_Assert_True(vm->sharedClassConfig->isBCIEnabled(vm));137romClass = loadData.romClass;138}139140}141}142}143144if (NULL == romClass) {145/* Attempt to create the romClass.146* When romClass exists in the cache, this call gives JVM a chance to trigger ClassFileLoadHook events.147* If ClassFileLoadHook event modifies the class file, it creates a new ROMClass but does not store it in shared class cache.148*/149romClass = createROMClassFromClassFile(vmThread, &loadData, localBuffer);150}151if (romClass) {152/* Host class can only be set for anonymous classes which are defined by Unsafe.defineAnonymousClass, or hidden classes.153* For other cases, host class is set to NULL.154*/155if ((NULL != hostClass) && (J2SE_VERSION(vm) >= J2SE_V11)) {156J9ROMClass *hostROMClass = hostClass->romClass;157/* This error-check should only be done for anonymous classes. */158Trc_BCU_Assert_True(isAnonFlagSet || isHiddenFlagSet);159/* From Java 9 and onwards, set IllegalArgumentException when host class and anonymous class have different packages. */160if (!hasSamePackageName(romClass, hostROMClass)) {161omrthread_monitor_exit(vm->classTableMutex);162setIllegalArgumentExceptionHostClassAnonClassHaveDifferentPackages(vmThread, romClass, hostROMClass);163freeAnonROMClass(vm, romClass);164goto done;165}166}167168/* report the ROM load events */169reportROMClassLoadEvents(vmThread, romClass, classLoader);170171/* localBuffer should not be NULL */172Trc_BCU_Assert_True(NULL != localBuffer);173174result = J9_VM_FUNCTION(vmThread, internalCreateRAMClassFromROMClass)(vmThread, classLoader, romClass, options,175NULL, loadData.protectionDomain, NULL, (IDATA)localBuffer->entryIndex, (IDATA)localBuffer->loadLocationType, NULL, hostClass);176if (NULL == result) {177/* ramClass creation failed - remember the orphan romClass for next time */178if (orphanROMClass != romClass) {179J9HashTable *hashTable = NULL;180181/* All access to the orphan table must be done while holding classTableMutex */182omrthread_monitor_enter(vm->classTableMutex);183hashTable = classLoader->romClassOrphansHashTable;184if (NULL == hashTable) {185hashTable = romClassHashTableNew(vm, 16);186classLoader->romClassOrphansHashTable = hashTable;187}188189/* It is possible to fail to create a hashTable, make sure one exists before trying to use it. */190if (NULL != hashTable) {191if (NULL != orphanROMClass) {192/* replace the previous entry */193Trc_BCU_romClassOrphansHashTableReplace(vmThread, classNameLength, className, romClass);194romClassHashTableReplace(hashTable, orphanROMClass, romClass);195} else {196Trc_BCU_romClassOrphansHashTableAdd(vmThread, classNameLength, className, romClass);197romClassHashTableAdd(hashTable, romClass);198}199}200omrthread_monitor_exit(vm->classTableMutex);201}202} else if (NULL != orphanROMClass) {203J9ROMClass *tableEntry = NULL;204/* ramClass creation succeeded - the orphanROMClass is no longer an orphan */205Trc_BCU_romClassOrphansHashTableDelete(vmThread, classNameLength, className, orphanROMClass);206/* All access to the orphan table must be done while holding classTableMutex.207* Ensure the entry is still in the table before removing it.208*/209omrthread_monitor_enter(vm->classTableMutex);210tableEntry = romClassHashTableFind(classLoader->romClassOrphansHashTable, className, classNameLength);211if (tableEntry == orphanROMClass) {212romClassHashTableDelete(classLoader->romClassOrphansHashTable, orphanROMClass);213} else {214Trc_BCU_internalDefineClass_orphanNotFound(vmThread, orphanROMClass, tableEntry);215}216omrthread_monitor_exit(vm->classTableMutex);217}218}219220done:221Trc_BCU_internalDefineClass_Exit(vmThread, className, result);222223return result;224}225226static void227throwNoClassDefFoundError(J9VMThread* vmThread, J9LoadROMClassData * loadData)228{229J9JavaVM* vm = vmThread->javaVM;230U_8* errorBuf;231UDATA bufSize;232PORT_ACCESS_FROM_JAVAVM(vm);233234Trc_BCU_throwNoClassDefFoundError_Entry(vmThread);235236bufSize = loadData->classNameLength;237errorBuf = j9mem_allocate_memory(bufSize + 1, J9MEM_CATEGORY_CLASSES);238239if (errorBuf) {240memcpy(errorBuf, loadData->className, bufSize);241errorBuf[bufSize] = (U_8) '\0';242243Trc_BCU_throwNoClassDefFoundError_ErrorBuf(vmThread, errorBuf);244245J9_VM_FUNCTION(vmThread, setCurrentExceptionUTF)(vmThread, J9VMCONSTANTPOOL_JAVALANGNOCLASSDEFFOUNDERROR, (char *) errorBuf);246247j9mem_free_memory(errorBuf);248} else {249J9_VM_FUNCTION(vmThread, setCurrentException)(vmThread, J9VMCONSTANTPOOL_JAVALANGNOCLASSDEFFOUNDERROR, NULL);250}251252Trc_BCU_throwNoClassDefFoundError_Exit(vmThread);253}254255/*256* Check to see if a class with this name is already loaded.257* If so, exit the classTableMutex, throw a NoClassDefFoundError (but only if throw-on-fail is set) and return the existing class.258* Otherwise return NULL.259*/260static J9Class*261checkForExistingClass(J9VMThread* vmThread, J9LoadROMClassData * loadData)262{263J9JavaVM* vm = vmThread->javaVM;264J9Class* existingClass;265266Trc_BCU_checkForExistingClass_Entry(vmThread, loadData->className, loadData->classLoader);267268existingClass = J9_VM_FUNCTION(vmThread, hashClassTableAt)(269loadData->classLoader,270loadData->className,271loadData->classNameLength);272273if (existingClass != NULL) {274/* error! a class with this name is already loaded in this class loader */275#ifdef J9VM_THR_PREEMPTIVE276omrthread_monitor_exit(vm->classTableMutex);277#endif278279Trc_BCU_checkForExistingClass_Exists(vmThread);280281if (loadData->options & J9_FINDCLASS_FLAG_THROW_ON_FAIL) {282throwNoClassDefFoundError(vmThread, loadData);283}284285Trc_BCU_checkForExistingClass_Exit(vmThread, existingClass);286return existingClass;287}288289Trc_BCU_checkForExistingClass_Exit(vmThread, NULL);290return NULL;291}292293static void294reportROMClassLoadEvents(J9VMThread* vmThread, J9ROMClass* romClass, J9ClassLoader* classLoader)295{296J9JavaVM* vm = vmThread->javaVM;297298/*299* J9HOOK_ROM_CLASS_LOAD300*/301TRIGGER_J9HOOK_VM_ROM_CLASS_LOAD(vm->hookInterface, vmThread, romClass);302}303304/*305* Warning: sender must hold class table mutex before calling.306*/307UDATA308internalLoadROMClass(J9VMThread * vmThread, J9LoadROMClassData *loadData, J9TranslationLocalBuffer *localBuffer)309{310J9JavaVM * vm = vmThread->javaVM;311UDATA result;312UDATA translationFlags;313UDATA classFileBytesReplacedByRIA = FALSE;314UDATA classFileBytesReplacedByRCA = FALSE;315U_8 * intermediateClassData = loadData->classData;316UDATA intermediateClassDataLength = loadData->classDataLength;317void* intermedtiateFreeUserData = NULL;318classDataFreeFunction intermediateFreeFunction = NULL;319PORT_ACCESS_FROM_VMC(vmThread);320321Trc_BCU_internalLoadROMClass_Entry(vmThread, loadData, loadData->classDataLength);322323#if 0324/*This block of code is disabled until CMVC 155494 is resolved. Otherwise it will block cbuilds*/325Trc_Assert_BCU_mustHaveVMAccess(vmThread);326#endif327328/* Call the class load hook to potentially replace the class data */329330if ((J9_ARE_NO_BITS_SET(loadData->options, J9_FINDCLASS_FLAG_ANON | J9_FINDCLASS_FLAG_HIDDEN) || (J2SE_VERSION(vm) <= J2SE_18))331&& (J9_EVENT_IS_HOOKED(vm->hookInterface, J9HOOK_VM_CLASS_LOAD_HOOK) || J9_EVENT_IS_HOOKED(vm->hookInterface, J9HOOK_VM_CLASS_LOAD_HOOK2))332) {333U_8 * classData = NULL;334char * className = NULL;335336Trc_BCU_internalLoadROMClass_ClassLoadHookEnter(vmThread);337338/* If shared cache is BCI enabled and the class is found in shared cache while loading then339* loadData->classData points to intermediate ROMClass,340* which needs to be converted back to classfile bytes before passing to the agents.341*/342if (J9_ARE_ALL_BITS_SET(loadData->options, J9_FINDCLASS_FLAG_SHRC_ROMCLASS_EXISTS)) {343U_8 * classFileBytes = NULL;344U_32 classFileBytesCount = 0;345IDATA result = 0;346J9ROMClass * intermediateROMClass = (J9ROMClass *) loadData->classData;347348result = j9bcutil_transformROMClass(vm, PORTLIB, intermediateROMClass, &classFileBytes, &classFileBytesCount);349if (BCT_ERR_NO_ERROR != result) {350Trc_BCU_internalLoadROMClass_ErrorInRecreatingClassfile(vmThread, intermediateROMClass, result);351goto done;352} else {353/* Successfully recreated classfile bytes from intermediate ROMClass. */354loadData->classData = classFileBytes;355loadData->classDataLength = classFileBytesCount;356}357} else {358result = BCT_ERR_OUT_OF_MEMORY;359/* Make a copy of the class data */360classData = j9mem_allocate_memory(loadData->classDataLength, J9MEM_CATEGORY_CLASSES);361if (classData == NULL) {362goto done;363}364/* If arraylets are in use, the classData will never be an object, it will have been copied before calling internalDefineClass */365memcpy(classData, loadData->classData, loadData->classDataLength);366if (loadData->freeFunction) {367loadData->freeFunction(loadData->freeUserData, loadData->classData);368}369loadData->classData = classData;370}371loadData->freeUserData = PORTLIB;372loadData->freeFunction = (classDataFreeFunction) OMRPORT_FROM_J9PORT(PORTLIB)->mem_free_memory;373loadData->classDataObject = NULL;374375/* Make a copy of the class name */376377if (loadData->classNameLength == 0) {378className = NULL;379} else {380UDATA classNameLength = loadData->classNameLength;381if (J9_ARE_ANY_BITS_SET(loadData->options, J9_FINDCLASS_FLAG_ANON | J9_FINDCLASS_FLAG_HIDDEN)) {382classNameLength -= (1 + ROM_ADDRESS_LENGTH);383}384className = j9mem_allocate_memory(classNameLength + 1, J9MEM_CATEGORY_CLASSES);385if (className == NULL) {386/* free class data before exiting */387if (NULL != classData) {388j9mem_free_memory(classData);389classData = NULL;390}391goto done;392}393memcpy(className, loadData->className, classNameLength);394className[classNameLength] = '\0';395}396397#ifdef J9VM_THR_PREEMPTIVE398omrthread_monitor_exit(vm->classTableMutex);399#endif400401if ((loadData->options & J9_FINDCLASS_FLAG_RETRANSFORMING) == 0) {402ALWAYS_TRIGGER_J9HOOK_VM_CLASS_LOAD_HOOK(vm->hookInterface,403vmThread,404loadData->classLoader,405loadData->protectionDomain,406loadData->classBeingRedefined,407className,408loadData->classData,409loadData->classDataLength,410loadData->freeUserData,411loadData->freeFunction,412classFileBytesReplacedByRIA);413}414415/* Record the bytes from the above hook call */416417intermediateClassData = loadData->classData;418intermediateClassDataLength = loadData->classDataLength;419intermedtiateFreeUserData = loadData->freeUserData;420intermediateFreeFunction = loadData->freeFunction;421loadData->freeFunction = NULL;422423#if defined(J9VM_OPT_JVMTI)424425/* Run the second transformation pass */426427ALWAYS_TRIGGER_J9HOOK_VM_CLASS_LOAD_HOOK2(vm->hookInterface,428vmThread,429loadData->classLoader,430loadData->protectionDomain,431loadData->classBeingRedefined,432className,433loadData->classData,434loadData->classDataLength,435loadData->freeUserData,436loadData->freeFunction,437classFileBytesReplacedByRCA);438#endif439440#ifdef J9VM_THR_PREEMPTIVE441omrthread_monitor_enter(vm->classTableMutex);442#endif443444if (className != NULL) {445j9mem_free_memory(className);446className = NULL;447}448449Trc_BCU_internalLoadROMClass_ClassLoadHookDone(vmThread);450}451452if (J9_ARE_ALL_BITS_SET(loadData->options, J9_FINDCLASS_FLAG_RETRANSFORMING)453&& (FALSE == classFileBytesReplacedByRCA)454) {455Trc_BCU_Assert_True(FALSE == classFileBytesReplacedByRIA);456457/* Class file is not modified during retransformation.458* If active ROMClass->intermediateClassData is a ROMClass then re-use it.459*/460if (!J9ROMCLASS_IS_INTERMEDIATE_DATA_A_CLASSFILE(loadData->classBeingRedefined->romClass)) {461loadData->romClass = (J9ROMClass *) J9ROMCLASS_INTERMEDIATECLASSDATA(loadData->classBeingRedefined->romClass);462result = BCT_ERR_NO_ERROR;463goto doneFreeMem;464}465}466467if (0 != (loadData->options & J9_FINDCLASS_FLAG_SHRC_ROMCLASS_EXISTS)) {468/* We are running with -Xshareclasses:enableBCI and have already found ROMClass in shared class cache. */469if ((FALSE == classFileBytesReplacedByRIA)470&& (FALSE == classFileBytesReplacedByRCA)471) {472/* Either we are using BCI agent which didn't modify the class file data or there is no BCI agent. */473Trc_BCU_Assert_NotEquals(NULL, loadData->romClass);474result = BCT_ERR_NO_ERROR;475goto doneFreeMem;476}477}478479/* Set up translation flags */480481#ifdef J9VM_ENV_LITTLE_ENDIAN482translationFlags = BCT_LittleEndianOutput;483#else484translationFlags = BCT_BigEndianOutput;485#endif486487/*488* RECORD_ALL is set by shared classes when it wishes to keep all debug information in the cache489* classCouldPossiblyBeShared() returns true when the classloader is a shared classes enabled loader AND the cache is NOT full490*491* do NOT attempt to strip debug information when RECORD_ALL is set AND the class could end up the cache.492*493*/494if ((J9VM_DEBUG_ATTRIBUTE_RECORD_ALL == (vm->requiredDebugAttributes & J9VM_DEBUG_ATTRIBUTE_RECORD_ALL))495&& classCouldPossiblyBeShared(vmThread, loadData)) {496/* Shared Classes has requested that all debug information be kept and the class will be shared. */497} else if (0 != (vm->runtimeFlags & J9_RUNTIME_XFUTURE)) {498/* Don't strip debug information with Xfuture */499} else {500/* either the class is not going to be shared -or- shared classes does not require the debug information to be maintained */501UDATA stripFlags = 0;502503if (0 == (vm->requiredDebugAttributes & J9VM_DEBUG_ATTRIBUTE_LOCAL_VARIABLE_TABLE)) {504stripFlags |= BCT_StripDebugVars;505}506if (0 == (vm->requiredDebugAttributes & J9VM_DEBUG_ATTRIBUTE_LINE_NUMBER_TABLE)) {507stripFlags |= BCT_StripDebugLines;508}509if (0 == (vm->requiredDebugAttributes & J9VM_DEBUG_ATTRIBUTE_SOURCE_FILE)) {510stripFlags |= BCT_StripDebugSource;511}512if (0 == (vm->requiredDebugAttributes & J9VM_DEBUG_ATTRIBUTE_SOURCE_DEBUG_EXTENSION)) {513stripFlags |= BCT_StripSourceDebugExtension;514}515516if (stripFlags == (BCT_StripDebugVars | BCT_StripDebugLines | BCT_StripDebugSource | BCT_StripSourceDebugExtension)) {517stripFlags = BCT_StripDebugAttributes;518}519translationFlags |= stripFlags;520}521522if (J9_ARE_ANY_BITS_SET(vm->runtimeFlags, J9_RUNTIME_VERIFY)) {523translationFlags |= BCT_StaticVerification;524}525526if (0 != (vm->runtimeFlags & J9_RUNTIME_XFUTURE)) {527translationFlags |= BCT_Xfuture;528} else {529/* Disable static verification for the bootstrap loader if Xfuture not present */530if ((vm->systemClassLoader == loadData->classLoader)531&& ((NULL == vm->bytecodeVerificationData) || (0 == (vm->bytecodeVerificationData->verificationFlags & J9_VERIFY_BOOTCLASSPATH_STATIC)))532&& (NULL == vm->sharedClassConfig)533) {534translationFlags &= ~BCT_StaticVerification;535}536}537538if (J9_ARE_ANY_BITS_SET(vm->runtimeFlags, J9_RUNTIME_ALWAYS_SPLIT_BYTECODES)) {539translationFlags |= BCT_AlwaysSplitBytecodes;540}541if (J9_ARE_ANY_BITS_SET(vm->extendedRuntimeFlags2, J9_EXTENDED_RUNTIME2_ENABLE_PREVIEW)) {542translationFlags |= BCT_EnablePreview;543}544/* Determine allowed class file version */545#ifdef J9VM_OPT_SIDECAR546{547/* majorVer is introduced to workaround JDK8 zOS 64bit compiler issue. */548U_32 majorVer = BCT_JavaMajorVersionShifted(JAVA_SPEC_VERSION);549translationFlags |= majorVer;550}551#endif552553/* TODO toss tracepoint?? Trc_BCU_internalLoadROMClass_AttemptExisting(vmThread, segment, romAvailable, bytesRequired); */554/* Attempt dynamic load */555result = callDynamicLoader(vmThread, loadData, intermediateClassData, intermediateClassDataLength, translationFlags, classFileBytesReplacedByRIA, classFileBytesReplacedByRCA, localBuffer);556557/* Free the class file bytes if necessary */558doneFreeMem:559if (NULL != intermediateFreeFunction) {560if (intermediateClassData == loadData->classData) {561loadData->freeFunction = NULL;562loadData->classData = NULL;563}564intermediateFreeFunction(intermedtiateFreeUserData, intermediateClassData);565intermediateClassData = NULL;566}567568if (loadData->freeFunction) {569loadData->freeFunction(loadData->freeUserData, loadData->classData);570loadData->freeFunction = NULL;571loadData->classData = NULL;572Trc_BCU_internalLoadROMClass_DoFree(vmThread);573}574575/* If the ROM class was created successfully, adjust the heapAlloc of the containing segment */576577done:578if (result == BCT_ERR_NO_ERROR) {579U_8 *intermediateData = J9ROMCLASS_INTERMEDIATECLASSDATA(loadData->romClass);580U_32 intermediateDataSize = loadData->romClass->intermediateClassDataLength;581BOOLEAN isSharedClassesEnabled = (NULL != vm->sharedClassConfig);582BOOLEAN isSharedClassesBCIEnabled = (TRUE == isSharedClassesEnabled) && (TRUE == vm->sharedClassConfig->isBCIEnabled(vm));583584Trc_BCU_internalLoadROMClass_NoError(vmThread, loadData->romClass);585586/* if romClass is in shared cache, ensure its intermediateClassData also points within shared cache */587if ((NULL != intermediateData)588&& (TRUE == j9shr_Query_IsAddressInReadWriteCache(vm, loadData->romClass, loadData->romClass->romSize))589) {590/* romClass and its intermediateData should be in the same cache */591Trc_BCU_Assert_True(TRUE == j9shr_Query_IsAddressInReadWriteCache(vm, intermediateData, intermediateDataSize));592}593594/* ROMClass should always have intermediate class data. */595Trc_BCU_Assert_True(NULL != intermediateData);596Trc_BCU_Assert_True(0 != intermediateDataSize);597598/* If retransformation is not allowed and shared cache is not BCI enabled,599* or the class file is not modified by RCA then600* romClass->intermediateClassData should point to its own ROMClass.601*/602if ((J9_ARE_NO_BITS_SET(vm->requiredDebugAttributes, J9VM_DEBUG_ATTRIBUTE_ALLOW_RETRANSFORM)603&& ((FALSE == isSharedClassesEnabled) || (FALSE == isSharedClassesBCIEnabled)))604|| (FALSE == classFileBytesReplacedByRCA)605) {606Trc_BCU_Assert_True(intermediateData == (U_8 *)loadData->romClass);607Trc_BCU_Assert_True(intermediateDataSize == loadData->romClass->romSize);608}609610/* If shared cache is BCI enabled and class file is modified then the ROMClass should not be in shared cache. */611if ((TRUE == isSharedClassesBCIEnabled)612&& ((TRUE == classFileBytesReplacedByRCA)613|| (TRUE == classFileBytesReplacedByRIA))614) {615Trc_BCU_Assert_True(FALSE == j9shr_Query_IsAddressInCache(vm, loadData->romClass, loadData->romClass->romSize));616617/* If class file is modified during load, then intermediate data of the class should not be in shared cache.618* But if the class is being re-transformed, then intermediate data may or may not be in shared cache.619*/620if (J9_ARE_NO_BITS_SET(loadData->options, J9_FINDCLASS_FLAG_RETRANSFORMING)621&& (NULL != intermediateData)622) {623Trc_BCU_Assert_True(FALSE == j9shr_Query_IsAddressInCache(vm, intermediateData, intermediateDataSize));624}625}626} else {627loadData->romClass = NULL;628loadData->romClassSegment = NULL;629}630631#if defined(J9VM_OPT_INVARIANT_INTERNING) && defined(J9VM_OPT_SHARED_CLASSES)632if (vm->sharedInvariantInternTable != NULL) {633/* This null check is added because a seg fault occurs otherwise. With the /g (code optimization) option enabled,634* the following if-statement never gets executed at run-time as it has an empty body. However, since the /g option635* is deprecated at Visual Studio 2010 compiler, the following if-statement is now executed at run-time and causes636* a seg fault. This is only a temporary workaround, and if necessary, it will be fixed as part of Fatih's work.637*/638if ((vm->sharedInvariantInternTable->flags & J9AVLTREE_DO_VERIFY_TREE_STRUCT_AND_ACCESS) == J9AVLTREE_DO_VERIFY_TREE_STRUCT_AND_ACCESS) {639/* If taking the string table lock fails in SCStoreTransaction, and SCStringTransaction640* the local string intern tree may still have been modified. In this case the call to641* avl_intern_verify() from the lock enter/exit functions will not have been run, so642* the local tree is checked here when the JVM is run with: -Xshareclasses:verifyInternTree643*644* For example when "-Xshareclasses:readonly" is used entering the string table lock will fail.645*/646/*TODO:FATIH:verify the table647avl_intern_verify(vm->dynamicLoadBuffers->invariantInternTree,648vm->dynamicLoadBuffers->invariantInternSharedPool,649NULL, FALSE);650*/651}652}653#endif654655Trc_BCU_internalLoadROMClass_Exit(vmThread, result);656657return result;658}659660static UDATA661callDynamicLoader(J9VMThread *vmThread, J9LoadROMClassData *loadData, U_8 * intermediateClassData, UDATA intermediateClassDataLength, UDATA translationFlags, UDATA classFileBytesReplacedByRIA, UDATA classFileBytesReplacedByRCA, J9TranslationLocalBuffer *localBuffer)662{663J9JavaVM * vm = vmThread->javaVM;664BOOLEAN createIntermediateROMClass = FALSE;665UDATA result = BCT_ERR_NO_ERROR;666U_8 *intermediateData = NULL;667UDATA intermediateDataLength = 0;668669/* Pass the verification of stackmaps control flags to be used by static verification (verifyClassFunction - j9bcv_verifyClassStructure) */670if (vm->bytecodeVerificationData) {671translationFlags |= (vm->bytecodeVerificationData->verificationFlags & (J9_VERIFY_IGNORE_STACK_MAPS | J9_VERIFY_NO_FALLBACK));672}673674if (J9_ARE_ANY_BITS_SET(loadData->options, J9_FINDCLASS_FLAG_SHRC_ROMCLASS_EXISTS)) {675if (TRUE == classFileBytesReplacedByRCA) {676if (FALSE == classFileBytesReplacedByRIA) {677/* Intermediate data (either classfile bytes or unmodified J9ROMClass)678* is already present in BCI enabled shared cache and679* only retransformation capable agent modified the classfile.680* In such case existing intermediate data in shared cache can be used681* as intermediate data for the new ROMClass.682*/683intermediateData = J9ROMCLASS_INTERMEDIATECLASSDATA(loadData->romClass);684intermediateDataLength = loadData->romClass->intermediateClassDataLength;685} else {686createIntermediateROMClass = TRUE;687}688}689/* While creating new ROMClass, existing ROMClass should not be passed to ROMClassCreationContext. */690loadData->romClass = NULL;691} else {692if (TRUE == classFileBytesReplacedByRCA) {693if (J9_ARE_ANY_BITS_SET(loadData->options, J9_FINDCLASS_FLAG_RETRANSFORMING)) {694/* class file bytes are modified during retransformation; use intermediate data from class being redefined */695intermediateData = J9ROMCLASS_INTERMEDIATECLASSDATA(loadData->classBeingRedefined->romClass);696intermediateDataLength = loadData->classBeingRedefined->romClass->intermediateClassDataLength;697} else {698createIntermediateROMClass = TRUE;699}700}701}702if (TRUE == createIntermediateROMClass) {703BOOLEAN useClassfileAsIntermediateData = FALSE;704705if (J9_ARE_ALL_BITS_SET(vm->extendedRuntimeFlags, J9_EXTENDED_RUNTIME_FORCE_CLASSFILE_AS_INTERMEDIATE_DATA)) {706useClassfileAsIntermediateData = TRUE;707} else {708/* Create a ROMClass out of intermediateClassData709* and store it as intermediate data in active J9ROMClass.710*/711J9LoadROMClassData intermediateLoadData;712IDATA rc;713714memset(&intermediateLoadData, 0, sizeof(J9LoadROMClassData));715intermediateLoadData.classBeingRedefined = NULL;716intermediateLoadData.className = loadData->className;717intermediateLoadData.classNameLength = loadData->classNameLength;718intermediateLoadData.classData = intermediateClassData;719intermediateLoadData.classDataLength = intermediateClassDataLength;720intermediateLoadData.classLoader = loadData->classLoader;721intermediateLoadData.options = loadData->options;722/* no need to set other fields in intermediateLoadData */723724rc = j9bcutil_buildRomClass(725&intermediateLoadData,726NULL, 0, vm,727translationFlags,728FALSE,729TRUE /* isIntermediateROMClass */,730localBuffer);731732if (BCT_ERR_NO_ERROR == rc) {733intermediateData = (U_8 *)intermediateLoadData.romClass;734intermediateDataLength = intermediateLoadData.romClass->romSize;735} else {736/* Failed to create intermediate ROMClass. Use classfile bytes as intermediate data */737Trc_BCU_callDynamicLoader_IntermediateROMClassCreationFailed(loadData, rc);738useClassfileAsIntermediateData = TRUE;739}740}741if (TRUE == useClassfileAsIntermediateData) {742intermediateData = intermediateClassData;743intermediateDataLength = intermediateClassDataLength;744translationFlags |= BCT_IntermediateDataIsClassfile;745}746}747748result = j9bcutil_buildRomClass(749loadData,750(U_8 *) intermediateData,751intermediateDataLength,752vm,753translationFlags,754classFileBytesReplacedByRIA | classFileBytesReplacedByRCA,755FALSE, /* isIntermediateROMClass */756localBuffer);757758if (BCT_ERR_NO_ERROR == result) {759/* The module of a class transformed by a JVMTI agent needs access to unnamed modules */760if ((J2SE_VERSION(vm) >= J2SE_V11)761&& (classFileBytesReplacedByRIA || classFileBytesReplacedByRCA)762) {763J9Module *module = J9_VM_FUNCTION(vmThread, findModuleForPackage)(vmThread, loadData->classLoader,764J9UTF8_DATA(J9ROMCLASS_CLASSNAME(loadData->romClass)), (U_32) packageNameLength(loadData->romClass));765if (NULL != module) {766module->isLoose = TRUE;767}768}769770if (J9_ARE_ANY_BITS_SET(vm->extendedRuntimeFlags, J9_EXTENDED_RUNTIME_RECREATE_CLASSFILE_ONLOAD)) {771U_8 * classFileBytes = NULL;772U_32 classFileBytesCount = 0;773U_8 * prevClassData = loadData->classData;774PORT_ACCESS_FROM_JAVAVM(vm);775776/* Use the ROMClass to recreate classfile bytes */777result = j9bcutil_transformROMClass(vm, PORTLIB, loadData->romClass, &classFileBytes, &classFileBytesCount);778if (BCT_ERR_NO_ERROR == result) {779loadData->classData = classFileBytes;780loadData->classDataLength = classFileBytesCount;781loadData->romClass = NULL;782783result = j9bcutil_buildRomClass(784loadData,785intermediateData,786intermediateDataLength,787vm,788translationFlags,789classFileBytesReplacedByRIA | classFileBytesReplacedByRCA,790FALSE, /* isIntermediateROMClass */791localBuffer);792793j9mem_free_memory(classFileBytes);794}795/* Restore classData */796loadData->classData = prevClassData;797}798}799return result;800}801802static J9ROMClass *803createROMClassFromClassFile(J9VMThread *currentThread, J9LoadROMClassData *loadData, J9TranslationLocalBuffer *localBuffer)804{805J9JavaVM * vm = currentThread->javaVM;806UDATA result = 0;807U_8 * errorUTF = NULL;808UDATA exceptionNumber = J9VMCONSTANTPOOL_JAVALANGCLASSFORMATERROR;809void * className = NULL;810UDATA classNameLength = 0;811J9ClassLoader * classLoader = NULL;812813/* Attempt to create the romClass */814815Trc_BCU_createROMClassFromClassFile_Entry(currentThread, loadData);816817result = internalLoadROMClass(currentThread, loadData, localBuffer);818className = loadData->className;819classNameLength = loadData->classNameLength;820classLoader = loadData->classLoader;821822/* If the romClass was successfully created, continue processing it */823824if (result == BCT_ERR_NO_ERROR) {825J9ROMClass * romClass = loadData->romClass;826J9UTF8 * romName = J9ROMCLASS_CLASSNAME(romClass);827828/* If a class name was specified, verify that the loaded class has the same name */829830Trc_BCU_createROMClassFromClassFile_postLoadNoErr(currentThread, J9UTF8_LENGTH(romName), J9UTF8_DATA(romName), classLoader, romClass, NULL); /* TODO update trace point*/831832Trc_BCU_createROMClassFromClassFile_Exit(currentThread, romClass);833return romClass;834}835836/* Always throw load errors */837838Trc_BCU_Assert_True(NULL != vm->dynamicLoadBuffers);839840switch (result) {841case BCT_ERR_INVALID_BYTECODE:842case BCT_ERR_STACK_MAP_FAILED:843case BCT_ERR_VERIFY_ERROR_INLINING:844case BCT_ERR_BYTECODE_TRANSLATION_FAILED:845case BCT_ERR_UNKNOWN_ANNOTATION:846#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)847case BCT_ERR_INVALID_VALUE_TYPE:848#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */849exceptionNumber = J9VMCONSTANTPOOL_JAVALANGVERIFYERROR;850break;851852case BCT_ERR_INVALID_ANNOTATION:853errorUTF = vm->dynamicLoadBuffers->classFileError;854exceptionNumber = J9VMCONSTANTPOOL_JAVALANGVERIFYERROR;855break;856857case BCT_ERR_ILLEGAL_PACKAGE_NAME:858exceptionNumber = J9VMCONSTANTPOOL_JAVALANGSECURITYEXCEPTION;859break;860861case BCT_ERR_OUT_OF_ROM:862case BCT_ERR_OUT_OF_MEMORY:863exceptionNumber = J9VMCONSTANTPOOL_JAVALANGOUTOFMEMORYERROR;864break;865866/*867* Error messages are contents of vm->dynamicLoadBuffers->classFileError with class name appended.868*869* We don't free vm->dynamicLoadBuffers->classFileError because it is also used as a classFileBuffer in ROMClassBuilder.870*/871case BCT_ERR_CLASS_READ:872exceptionNumber = ((J9CfrError *)vm->dynamicLoadBuffers->classFileError)->errorAction;873/* FALLTHROUGH */874875case BCT_ERR_GENERIC_ERROR_CUSTOM_MSG: {876/* default value for exceptionNumber (J9VMCONSTANTPOOL_JAVALANGCLASSFORMATERROR) assigned before switch */877errorUTF = (U_8 *)buildVerifyErrorString(vm, (J9CfrError *)vm->dynamicLoadBuffers->classFileError, className, classNameLength);878break;879}880881/*882* Error messages are contents of vm->dynamicLoadBuffers->classFileError if anything is assigned883* otherwise just the classname.884*/885case BCT_ERR_INVALID_CLASS_TYPE:886case BCT_ERR_CLASS_NAME_MISMATCH:887exceptionNumber = J9VMCONSTANTPOOL_JAVALANGNOCLASSDEFFOUNDERROR;888/* FALLTHROUGH */889890default:891/* BCT_ERR_GENERIC_ERROR: default value for exceptionNumber (J9VMCONSTANTPOOL_JAVALANGCLASSFORMATERROR)892* assigned before switch */893errorUTF = vm->dynamicLoadBuffers->classFileError;894if (NULL == errorUTF) {895PORT_ACCESS_FROM_JAVAVM(vm);896errorUTF = j9mem_allocate_memory(loadData->classNameLength + 1, J9MEM_CATEGORY_CLASSES);897if (NULL != errorUTF) {898memcpy(errorUTF, loadData->className, loadData->classNameLength);899errorUTF[loadData->classNameLength] = (U_8) '\0';900}901}902break;903}904905Trc_BCU_Assert_True((NULL == vm->dynamicLoadBuffers->classFileError) || (NULL != errorUTF));906vm->dynamicLoadBuffers->classFileError = NULL;907908#ifdef J9VM_THR_PREEMPTIVE909omrthread_monitor_exit(vm->classTableMutex);910#endif911912Trc_BCU_createROMClassFromClassFile_throwError(currentThread, exceptionNumber);913914/* Do not throw OutOfMemoryError here, instead set the private flags bit */915916if (exceptionNumber == J9VMCONSTANTPOOL_JAVALANGOUTOFMEMORYERROR) {917currentThread->privateFlags |= J9_PRIVATE_FLAGS_CLOAD_NO_MEM;918/*Trc_BCU_internalLoadROMClass_NoMemory(vmThread);*/919} else {920if (errorUTF == NULL) {921J9_VM_FUNCTION(currentThread, setCurrentException)(currentThread, exceptionNumber, NULL);922} else {923PORT_ACCESS_FROM_JAVAVM(vm);924J9_VM_FUNCTION(currentThread, setCurrentExceptionUTF)(currentThread, exceptionNumber, (const char*)errorUTF);925j9mem_free_memory(errorUTF);926}927}928929Trc_BCU_createROMClassFromClassFile_Exit(currentThread, NULL);930return NULL;931}932933static UDATA934classCouldPossiblyBeShared(J9VMThread * vmThread, J9LoadROMClassData * loadData)935{936J9JavaVM * vm = vmThread->javaVM;937return ((0 != (loadData->classLoader->flags & J9CLASSLOADER_SHARED_CLASSES_ENABLED)) && !j9shr_Query_IsCacheFull(vm));938}939940/* Return TRUE if anonClass and hostClass have the same package name.941* If anonymous class has no package name, then consider it to be part942* of host class's package. Return TRUE if anonymous class has no943* package name. Otherwise, return FALSE.944*/945static BOOLEAN946hasSamePackageName(J9ROMClass *anonROMClass, J9ROMClass *hostROMClass) {947BOOLEAN rc = FALSE;948const UDATA anonClassPackageNameLength = packageNameLength(anonROMClass);949950if (0 == anonClassPackageNameLength) {951rc = TRUE;952} else {953const U_8 *anonClassName = J9UTF8_DATA(J9ROMCLASS_CLASSNAME(anonROMClass));954const U_8 *hostClassName = J9UTF8_DATA(J9ROMCLASS_CLASSNAME(hostROMClass));955const UDATA hostClassPackageNameLength = packageNameLength(hostROMClass);956if (J9UTF8_DATA_EQUALS(anonClassName, anonClassPackageNameLength, hostClassName, hostClassPackageNameLength)) {957rc = TRUE;958}959}960961return rc;962}963964/* Create error message with host class and anonymous class. */965static char*966createErrorMessage(J9VMThread *vmStruct, J9ROMClass *anonROMClass, J9ROMClass *hostROMClass, const char* errorMsg) {967PORT_ACCESS_FROM_VMC(vmStruct);968char *buf = NULL;969970if (NULL != errorMsg) {971UDATA bufLen = 0;972const J9UTF8 *anonClassName = J9ROMCLASS_CLASSNAME(anonROMClass);973const J9UTF8 *hostClassName = J9ROMCLASS_CLASSNAME(hostROMClass);974const U_8 *hostClassNameData = J9UTF8_DATA(hostClassName);975const U_8 *anonClassNameData = J9UTF8_DATA(anonClassName);976const UDATA hostClassNameLength = J9UTF8_LENGTH(hostClassName);977978/* Anonymous class name has trailing digits. Example - "test/DummyClass/00000000442F098".979* The code below removes the trailing digits, "/00000000442F098", from the anonymous class name.980*/981IDATA anonClassNameLength = J9UTF8_LENGTH(anonClassName) - 1;982for (; anonClassNameLength >= 0; anonClassNameLength--) {983if (anonClassNameData[anonClassNameLength] == '/') {984break;985}986}987988bufLen = j9str_printf(PORTLIB, NULL, 0, errorMsg,989hostClassNameLength, hostClassNameData,990anonClassNameLength, anonClassNameData);991if (bufLen > 0) {992buf = j9mem_allocate_memory(bufLen, OMRMEM_CATEGORY_VM);993if (NULL != buf) {994j9str_printf(PORTLIB, buf, bufLen, errorMsg,995hostClassNameLength, hostClassNameData,996anonClassNameLength, anonClassNameData);997}998}999}10001001return buf;1002}10031004/* From Java 9 and onwards, set IllegalArgumentException when host class and anonymous class have different packages. */1005static void1006setIllegalArgumentExceptionHostClassAnonClassHaveDifferentPackages(J9VMThread *vmStruct, J9ROMClass *anonROMClass, J9ROMClass *hostROMClass) {1007PORT_ACCESS_FROM_VMC(vmStruct);1008const J9JavaVM *vm = vmStruct->javaVM;10091010/* Construct error string */1011const char *errorMsg = j9nls_lookup_message(J9NLS_DO_NOT_PRINT_MESSAGE_TAG | J9NLS_DO_NOT_APPEND_NEWLINE, J9NLS_JCL_HOSTCLASS_ANONCLASS_DIFFERENT_PACKAGES, NULL);1012char *buf = createErrorMessage(vmStruct, anonROMClass, hostROMClass, errorMsg);1013J9_VM_FUNCTION(vmStruct, setCurrentExceptionUTF)(vmStruct, J9VMCONSTANTPOOL_JAVALANGILLEGALARGUMENTEXCEPTION, buf);1014j9mem_free_memory(buf);1015}10161017/* Free the memory segment corresponding to the anonymous ROM class. */1018static void1019freeAnonROMClass(J9JavaVM *vm, J9ROMClass *romClass) {1020if (NULL != romClass) {1021omrthread_monitor_t segmentMutex = vm->classMemorySegments->segmentMutex;1022omrthread_monitor_enter(segmentMutex);1023{1024J9MemorySegment **previousSegmentPointerROM = &vm->anonClassLoader->classSegments;1025J9MemorySegment *segmentROM = *previousSegmentPointerROM;1026BOOLEAN foundMemorySegment = FALSE;10271028/* Walk all anonymous classloader's ROM memory segments. If ROM class1029* is allocated there it would be one per segment.1030*/1031while (NULL != segmentROM) {1032J9MemorySegment *nextSegmentROM = segmentROM->nextSegmentInClassLoader;1033if (J9_ARE_ALL_BITS_SET(segmentROM->type, MEMORY_TYPE_ROM_CLASS)1034&& ((J9ROMClass *)segmentROM->heapBase == romClass)1035) {1036foundMemorySegment = TRUE;1037/* Found memory segment corresponding to the ROM class. Remove1038* this memory segment from the list.1039*/1040*previousSegmentPointerROM = nextSegmentROM;1041/* Free memory segment corresponding to the ROM class. */1042J9_VM_FUNCTION_VIA_JAVAVM(vm, freeMemorySegment)(vm, segmentROM, 1);1043break;1044}1045previousSegmentPointerROM = &segmentROM->nextSegmentInClassLoader;1046segmentROM = nextSegmentROM;1047}1048/* Memory segment should always be found if the ROM class exists. */1049Trc_BCU_Assert_True(foundMemorySegment);1050}1051omrthread_monitor_exit(segmentMutex);1052}1053}10541055#endif /* J9VM_OPT_DYNAMIC_LOAD_SUPPORT */ /* End File Level Build Flags */105610571058