Path: blob/master/runtime/jcl/common/jcldefine.c
6000 views
/*******************************************************************************1* Copyright (c) 1998, 2021 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 "j9.h"23#include "j9consts.h"24#include "jclprots.h"25#include "j9protos.h"26#include "j9jclnls.h"2728jclass29defineClassCommon(JNIEnv *env, jobject classLoaderObject,30jstring className, jbyteArray classRep, jint offset, jint length, jobject protectionDomain, UDATA *options, J9Class *hostClass, J9ClassPatchMap *patchMap, BOOLEAN validateName)31{32#ifdef J9VM_OPT_DYNAMIC_LOAD_SUPPORT3334/* Try a couple of GC passes (1 doesn't sem to be enough), but don't try forever */35#define MAX_RETRY_COUNT 23637J9VMThread *currentThread = (J9VMThread *)env;38J9JavaVM *vm = currentThread->javaVM;39J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;40J9TranslationBufferSet *dynFuncs = NULL;41J9ClassLoader *classLoader = NULL;42UDATA retried = FALSE;43UDATA utf8Length = 0;44char utf8NameStackBuffer[J9VM_PACKAGE_NAME_BUFFER_LENGTH];45U_8 *utf8Name = NULL;46U_8 *classBytes = NULL;47J9Class *clazz = NULL;48jclass result = NULL;49PORT_ACCESS_FROM_JAVAVM(vm);50UDATA isContiguousClassBytes = 0;51J9ROMClass *loadedClass = NULL;52U_8 *tempClassBytes = NULL;53I_32 tempLength = 0;54J9TranslationLocalBuffer localBuffer = {J9_CP_INDEX_NONE, LOAD_LOCATION_UNKNOWN, NULL};5556if (vm->dynamicLoadBuffers == NULL) {57throwNewInternalError(env, "Dynamic loader is unavailable");58goto done;59}60dynFuncs = vm->dynamicLoadBuffers;6162if (classRep == NULL) {63throwNewNullPointerException(env, NULL);64goto done;65}6667if ((patchMap != NULL) && (patchMap->size != 0)) {68localBuffer.patchMap = patchMap;69}7071vmFuncs->internalEnterVMFromJNI(currentThread);72isContiguousClassBytes = J9ISCONTIGUOUSARRAY(currentThread, *(J9IndexableObject **)classRep);73if (!isContiguousClassBytes) {74vmFuncs->internalExitVMToJNI(currentThread);75/* Make a "flat" copy of classRep */76if (length < 0) {77throwNewIndexOutOfBoundsException(env, NULL);78goto done;79}80classBytes = j9mem_allocate_memory(length, J9MEM_CATEGORY_CLASSES);81if (classBytes == NULL) {82vmFuncs->throwNativeOOMError(env, 0, 0);83goto done;84}85(*env)->GetByteArrayRegion(env, classRep, offset, length, (jbyte *)classBytes);86if ((*env)->ExceptionCheck(env)) {87j9mem_free_memory(classBytes);88goto done;89}90vmFuncs->internalEnterVMFromJNI(currentThread);91}9293/* Allocate and initialize a UTF8 copy of the Unicode class-name */94if (NULL != className) {95j9object_t classNameObject = J9_JNI_UNWRAP_REFERENCE(className);96UDATA stringFlags = J9_STR_NULL_TERMINATE_RESULT;9798if (!validateName) {99stringFlags |= J9_STR_XLAT;100}101102utf8Name = (U_8*)vmFuncs->copyStringToUTF8WithMemAlloc(currentThread, classNameObject, stringFlags, "", 0, utf8NameStackBuffer, J9VM_PACKAGE_NAME_BUFFER_LENGTH, &utf8Length);103104if (NULL == utf8Name) {105vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);106goto done;107}108109if (validateName && (CLASSNAME_INVALID == vmFuncs->verifyQualifiedName(currentThread, utf8Name, utf8Length, CLASSNAME_VALID_NON_ARRARY))) {110/* We don't yet know if the class being defined is exempt. Setting this option tells111* defineClassCommon() to fail if it discovers that the class is not exempt. That failure112* is distinguished by returning NULL with no exception pending.113*/114*options |= J9_FINDCLASS_FLAG_NAME_IS_INVALID;115}116117if (J9_ARE_ANY_BITS_SET(*options, J9_FINDCLASS_FLAG_HIDDEN | J9_FINDCLASS_FLAG_UNSAFE)) {118/*119* Prevent generated LambdaForm classes from MethodHandles to be stored to the shared cache.120* When there are a large number of such classes in the shared cache, they trigger a lot of class comparisons.121* Performance can be much worse (compared to shared cache turned off).122*/123#define J9NON_SHARING_CLASS_NAME "java/lang/invoke/LambdaForm$"124if ((utf8Length > LITERAL_STRLEN(J9NON_SHARING_CLASS_NAME))125&& J9UTF8_LITERAL_EQUALS(utf8Name, LITERAL_STRLEN(J9NON_SHARING_CLASS_NAME), J9NON_SHARING_CLASS_NAME)126) {127*options |= J9_FINDCLASS_FLAG_DO_NOT_SHARE;128}129#undef J9NON_SHARING_CLASS_NAME130}131}132133if (isContiguousClassBytes) {134/* For ARRAYLETS case, we get free range checking from GetByteArrayRegion JNI call */135if ((offset < 0) || (length < 0) ||136(((U_32)offset + (U_32)length) > J9INDEXABLEOBJECT_SIZE(currentThread, *(J9IndexableObject **)classRep))) {137vmFuncs->setCurrentException(currentThread, J9VMCONSTANTPOOL_JAVALANGINDEXOUTOFBOUNDSEXCEPTION, NULL);138goto done;139}140}141142classLoader = J9VMJAVALANGCLASSLOADER_VMREF(currentThread, J9_JNI_UNWRAP_REFERENCE(classLoaderObject));143144if (NULL == classLoader) {145classLoader = vmFuncs->internalAllocateClassLoader(vm, J9_JNI_UNWRAP_REFERENCE(classLoaderObject));146if (NULL == classLoader) {147goto done;148}149}150151retry:152153omrthread_monitor_enter(vm->classTableMutex);154/* Hidden class is never added into the hash table */155if (J9_ARE_NO_BITS_SET(*options, J9_FINDCLASS_FLAG_HIDDEN)) {156if (NULL != vmFuncs->hashClassTableAt(classLoader, utf8Name, utf8Length)) {157/* Bad, we have already defined this class - fail */158omrthread_monitor_exit(vm->classTableMutex);159if (J9_ARE_NO_BITS_SET(*options, J9_FINDCLASS_FLAG_NAME_IS_INVALID)) {160vmFuncs->setCurrentExceptionNLSWithArgs(currentThread, J9NLS_JCL_DUPLICATE_CLASS_DEFINITION, J9VMCONSTANTPOOL_JAVALANGLINKAGEERROR, utf8Length, utf8Name);161}162goto done;163}164}165166if (isContiguousClassBytes) {167/* Always re-load the classBytes pointer, as GC required in OutOfMemory case may have moved things */168/* TMP_J9JAVACONTIGUOUSARRAYOFBYTE_EA returns I_8 * (since Java bytes are I_8) so this cast will silence the warning */169classBytes = (U_8 *) TMP_J9JAVACONTIGUOUSARRAYOFBYTE_EA(currentThread, *(J9IndexableObject **)classRep, offset);170}171172tempClassBytes = classBytes;173tempLength = length;174175/* Try to find classLocation. Ignore return code because there are valid cases where it might not find it (ie. bytecode spinning).176* If the class is not found the default class location is fine.177*/178dynFuncs->findLocallyDefinedClassFunction(currentThread, NULL, utf8Name, (U_32) utf8Length, classLoader, (UDATA) FALSE, &localBuffer);179180/* skip if we are anonClass or hidden classes */181if (J9_ARE_NO_BITS_SET(*options, J9_FINDCLASS_FLAG_ANON | J9_FINDCLASS_FLAG_HIDDEN)) {182/* Check for romClass cookie, it indicates that we are defining a class out of a JXE not from class bytes */183184loadedClass = vmFuncs->romClassLoadFromCookie(currentThread, utf8Name, utf8Length, classBytes, (UDATA) length);185186if (NULL != loadedClass) {187/* An existing ROMClass is found in the shared class cache.188* If -Xshareclasses:enableBCI is present, need to give VM a chance to trigger ClassFileLoadHook event.189*/190if ((NULL == vm->sharedClassConfig) || (0 == vm->sharedClassConfig->isBCIEnabled(vm))) {191clazz = vmFuncs->internalCreateRAMClassFromROMClass(currentThread,192classLoader,193loadedClass,1940,195NULL,196protectionDomain ? *(j9object_t*)protectionDomain : NULL,197NULL,198J9_CP_INDEX_NONE,199localBuffer.loadLocationType,200NULL,201hostClass);202/* Done if a class was found or and exception is pending, otherwise try to define the bytes */203if ((clazz != NULL) || (currentThread->currentException != NULL)) {204goto done;205} else {206loadedClass = NULL;207}208} else {209tempClassBytes = J9ROMCLASS_INTERMEDIATECLASSDATA(loadedClass);210tempLength = loadedClass->intermediateClassDataLength;211*options |= J9_FINDCLASS_FLAG_SHRC_ROMCLASS_EXISTS;212}213}214}215216/* The defineClass helper requires you hold the class table mutex and releases it for you */217218clazz = dynFuncs->internalDefineClassFunction(currentThread,219utf8Name, utf8Length,220tempClassBytes, (UDATA) tempLength, NULL,221classLoader,222protectionDomain ? *(j9object_t*)protectionDomain : NULL,223*options | J9_FINDCLASS_FLAG_THROW_ON_FAIL | J9_FINDCLASS_FLAG_NO_CHECK_FOR_EXISTING_CLASS,224loadedClass,225hostClass,226&localBuffer);227228/* If OutOfMemory, try a GC to free up some memory */229230if (currentThread->privateFlags & J9_PRIVATE_FLAGS_CLOAD_NO_MEM) {231if (!retried) {232/*Trc_VM_internalFindClass_gcAndRetry(vmThread);*/233currentThread->javaVM->memoryManagerFunctions->j9gc_modron_global_collect_with_overrides(currentThread, J9MMCONSTANT_EXPLICIT_GC_NATIVE_OUT_OF_MEMORY);234retried = TRUE;235goto retry;236}237vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);238}239240done:241if (NULL == clazz) {242if (J9_ARE_ANY_BITS_SET(*options, J9_FINDCLASS_FLAG_NAME_IS_INVALID)) {243/*244* The caller signalled that the name is invalid. Leave the result NULL and245* clear any pending exception; the caller will throw NoClassDefFoundError.246*/247currentThread->currentException = NULL;248currentThread->privateFlags &= ~(UDATA)J9_PRIVATE_FLAGS_REPORT_EXCEPTION_THROW;249} else if (NULL == currentThread->currentException) {250/* should not get here -- throw the default exception just in case */251vmFuncs->setCurrentException(currentThread, J9VMCONSTANTPOOL_JAVALANGCLASSFORMATERROR, NULL);252}253} else {254result = vmFuncs->j9jni_createLocalRef(env, J9VM_J9CLASS_TO_HEAPCLASS(clazz));255}256257vmFuncs->internalExitVMToJNI(currentThread);258259if ((U_8*)utf8NameStackBuffer != utf8Name) {260j9mem_free_memory(utf8Name);261}262263if (!isContiguousClassBytes) {264j9mem_free_memory(classBytes);265}266267return result;268269#else /* J9VM_OPT_DYNAMIC_LOAD_SUPPORT */270throwNewInternalError(env, "Dynamic loading not supported");271return NULL;272#endif /* J9VM_OPT_DYNAMIC_LOAD_SUPPORT */273}274275276