Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/bcutil/defineclass.c
5985 views
1
/*******************************************************************************
2
* Copyright (c) 1991, 2022 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* 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-exception
21
*******************************************************************************/
22
23
#include <stdlib.h>
24
#include <string.h>
25
26
#include "j9.h"
27
#include "j9port.h"
28
#include "j9protos.h"
29
#include "j9consts.h"
30
#include "ut_j9bcu.h"
31
#include "objhelp.h"
32
#include "j2sever.h"
33
#include "bcutil_api.h"
34
#include "bcutil_internal.h"
35
#include "SCQueryFunctions.h"
36
#include "j9jclnls.h"
37
38
#if defined(J9VM_OPT_DYNAMIC_LOAD_SUPPORT) /* File Level Build Flags */
39
40
static UDATA classCouldPossiblyBeShared(J9VMThread * vmThread, J9LoadROMClassData * loadData);
41
static J9ROMClass * createROMClassFromClassFile (J9VMThread *currentThread, J9LoadROMClassData * loadData, J9TranslationLocalBuffer *localBuffer);
42
static void throwNoClassDefFoundError (J9VMThread* vmThread, J9LoadROMClassData * loadData);
43
static void reportROMClassLoadEvents (J9VMThread* vmThread, J9ROMClass* romClass, J9ClassLoader* classLoader);
44
static J9Class* checkForExistingClass (J9VMThread* vmThread, J9LoadROMClassData * loadData);
45
static UDATA callDynamicLoader(J9VMThread* vmThread, J9LoadROMClassData *loadData, U_8 * intermediateClassData, UDATA intermediateClassDataLength, UDATA translationFlags, UDATA classFileBytesReplacedByRIA, UDATA classFileBytesReplacedByRCA, J9TranslationLocalBuffer *localBuffer);
46
47
static BOOLEAN hasSamePackageName(J9ROMClass *anonROMClass, J9ROMClass *hostROMClass);
48
static char* createErrorMessage(J9VMThread *vmStruct, J9ROMClass *anonROMClass, J9ROMClass *hostROMClass, const char* errorMsg);
49
static void setIllegalArgumentExceptionHostClassAnonClassHaveDifferentPackages(J9VMThread *vmStruct, J9ROMClass *anonROMClass, J9ROMClass *hostROMClass);
50
static void freeAnonROMClass(J9JavaVM *vm, J9ROMClass *romClass);
51
52
#define GET_CLASS_LOADER_FROM_ID(vm, classLoader) ((classLoader) != NULL ? (classLoader) : (vm)->systemClassLoader)
53
54
/*
55
* Warning: sender must hold class table mutex before calling.
56
*/
57
J9Class*
58
internalDefineClass(
59
J9VMThread* vmThread,
60
void* className,
61
UDATA classNameLength,
62
U_8* classData,
63
UDATA classDataLength,
64
j9object_t classDataObject,
65
J9ClassLoader* classLoader,
66
j9object_t protectionDomain,
67
UDATA options,
68
J9ROMClass *existingROMClass,
69
J9Class *hostClass,
70
J9TranslationLocalBuffer *localBuffer)
71
{
72
J9JavaVM* vm = vmThread->javaVM;
73
J9ROMClass* orphanROMClass = NULL;
74
J9ROMClass* romClass = NULL;
75
J9Class* result = NULL;
76
J9LoadROMClassData loadData = {0};
77
BOOLEAN isAnonFlagSet = J9_ARE_ALL_BITS_SET(options, J9_FINDCLASS_FLAG_ANON);
78
BOOLEAN isHiddenFlagSet = J9_ARE_ALL_BITS_SET(options, J9_FINDCLASS_FLAG_HIDDEN);
79
80
/* This trace point is obsolete. It is retained only because j9vm test depends on it.
81
* Once j9vm tests are fixed, it would be marked as Obsolete in j9bcu.tdf
82
*/
83
Trc_BCU_internalDefineClass_Entry(vmThread, className, classNameLength, className);
84
85
Trc_BCU_internalDefineClass_Entry1(vmThread, className, classNameLength, className, existingROMClass);
86
Trc_BCU_internalDefineClass_FullData(vmThread, classDataLength, classData, classLoader);
87
88
classLoader = GET_CLASS_LOADER_FROM_ID(vm, classLoader);
89
90
/* remember the current classpath entry so we can record it at the end */
91
vmThread->privateFlags &= ~J9_PRIVATE_FLAGS_CLOAD_NO_MEM;
92
93
loadData.classBeingRedefined = NULL;
94
loadData.className = className;
95
loadData.classNameLength = classNameLength;
96
loadData.classData = classData;
97
loadData.classDataLength = classDataLength;
98
loadData.classDataObject = classDataObject;
99
100
loadData.classLoader = classLoader;
101
if (isAnonFlagSet) {
102
loadData.classLoader = vm->anonClassLoader;
103
}
104
loadData.protectionDomain = protectionDomain;
105
loadData.options = options;
106
loadData.freeUserData = NULL;
107
loadData.freeFunction = NULL;
108
loadData.romClass = existingROMClass;
109
110
loadData.hostPackageName = NULL;
111
loadData.hostPackageLength = 0;
112
if (isAnonFlagSet && (J2SE_VERSION(vm) >= J2SE_V11)) {
113
J9ROMClass *hostROMClass = hostClass->romClass;
114
loadData.hostPackageName = J9UTF8_DATA(J9ROMCLASS_CLASSNAME(hostROMClass));
115
loadData.hostPackageLength = packageNameLength(hostROMClass);
116
}
117
118
if (J9_ARE_NO_BITS_SET(options, J9_FINDCLASS_FLAG_NO_CHECK_FOR_EXISTING_CLASS)) {
119
/* For non-bootstrap classes, this check is done in jcldefine.c:defineClassCommon(). */
120
if (checkForExistingClass(vmThread, &loadData) != NULL) {
121
Trc_BCU_internalDefineClass_Exit(vmThread, className, NULL);
122
return NULL;
123
}
124
}
125
126
if (!isAnonFlagSet && !isHiddenFlagSet) {
127
/* See if there's already an orphan romClass available - still own classTableMutex at this point */
128
if (NULL != classLoader->romClassOrphansHashTable) {
129
orphanROMClass = romClassHashTableFind(classLoader->romClassOrphansHashTable, className, classNameLength);
130
if (NULL != orphanROMClass) {
131
loadData.romClass = orphanROMClass;
132
/* If enableBCI is specified, class was loaded from shared cache and previous attempt to create RAMClass failed,
133
* we can use the orphanROMClass created in previous attempt.
134
*/
135
if (0 != (loadData.options & J9_FINDCLASS_FLAG_SHRC_ROMCLASS_EXISTS)) {
136
Trc_BCU_Assert_NotEquals(NULL, vm->sharedClassConfig);
137
Trc_BCU_Assert_True(vm->sharedClassConfig->isBCIEnabled(vm));
138
romClass = loadData.romClass;
139
}
140
141
}
142
}
143
}
144
145
if (NULL == romClass) {
146
/* Attempt to create the romClass.
147
* When romClass exists in the cache, this call gives JVM a chance to trigger ClassFileLoadHook events.
148
* If ClassFileLoadHook event modifies the class file, it creates a new ROMClass but does not store it in shared class cache.
149
*/
150
romClass = createROMClassFromClassFile(vmThread, &loadData, localBuffer);
151
}
152
if (romClass) {
153
/* Host class can only be set for anonymous classes which are defined by Unsafe.defineAnonymousClass, or hidden classes.
154
* For other cases, host class is set to NULL.
155
*/
156
if ((NULL != hostClass) && (J2SE_VERSION(vm) >= J2SE_V11)) {
157
J9ROMClass *hostROMClass = hostClass->romClass;
158
/* This error-check should only be done for anonymous classes. */
159
Trc_BCU_Assert_True(isAnonFlagSet || isHiddenFlagSet);
160
/* From Java 9 and onwards, set IllegalArgumentException when host class and anonymous class have different packages. */
161
if (!hasSamePackageName(romClass, hostROMClass)) {
162
omrthread_monitor_exit(vm->classTableMutex);
163
setIllegalArgumentExceptionHostClassAnonClassHaveDifferentPackages(vmThread, romClass, hostROMClass);
164
freeAnonROMClass(vm, romClass);
165
goto done;
166
}
167
}
168
169
/* report the ROM load events */
170
reportROMClassLoadEvents(vmThread, romClass, classLoader);
171
172
/* localBuffer should not be NULL */
173
Trc_BCU_Assert_True(NULL != localBuffer);
174
175
result = J9_VM_FUNCTION(vmThread, internalCreateRAMClassFromROMClass)(vmThread, classLoader, romClass, options,
176
NULL, loadData.protectionDomain, NULL, (IDATA)localBuffer->entryIndex, (IDATA)localBuffer->loadLocationType, NULL, hostClass);
177
if (NULL == result) {
178
/* ramClass creation failed - remember the orphan romClass for next time */
179
if (orphanROMClass != romClass) {
180
J9HashTable *hashTable = NULL;
181
182
/* All access to the orphan table must be done while holding classTableMutex */
183
omrthread_monitor_enter(vm->classTableMutex);
184
hashTable = classLoader->romClassOrphansHashTable;
185
if (NULL == hashTable) {
186
hashTable = romClassHashTableNew(vm, 16);
187
classLoader->romClassOrphansHashTable = hashTable;
188
}
189
190
/* It is possible to fail to create a hashTable, make sure one exists before trying to use it. */
191
if (NULL != hashTable) {
192
if (NULL != orphanROMClass) {
193
/* replace the previous entry */
194
Trc_BCU_romClassOrphansHashTableReplace(vmThread, classNameLength, className, romClass);
195
romClassHashTableReplace(hashTable, orphanROMClass, romClass);
196
} else {
197
Trc_BCU_romClassOrphansHashTableAdd(vmThread, classNameLength, className, romClass);
198
romClassHashTableAdd(hashTable, romClass);
199
}
200
}
201
omrthread_monitor_exit(vm->classTableMutex);
202
}
203
} else if (NULL != orphanROMClass) {
204
J9ROMClass *tableEntry = NULL;
205
/* ramClass creation succeeded - the orphanROMClass is no longer an orphan */
206
Trc_BCU_romClassOrphansHashTableDelete(vmThread, classNameLength, className, orphanROMClass);
207
/* All access to the orphan table must be done while holding classTableMutex.
208
* Ensure the entry is still in the table before removing it.
209
*/
210
omrthread_monitor_enter(vm->classTableMutex);
211
tableEntry = romClassHashTableFind(classLoader->romClassOrphansHashTable, className, classNameLength);
212
if (tableEntry == orphanROMClass) {
213
romClassHashTableDelete(classLoader->romClassOrphansHashTable, orphanROMClass);
214
} else {
215
Trc_BCU_internalDefineClass_orphanNotFound(vmThread, orphanROMClass, tableEntry);
216
}
217
omrthread_monitor_exit(vm->classTableMutex);
218
}
219
}
220
221
done:
222
Trc_BCU_internalDefineClass_Exit(vmThread, className, result);
223
224
return result;
225
}
226
227
static void
228
throwNoClassDefFoundError(J9VMThread* vmThread, J9LoadROMClassData * loadData)
229
{
230
J9JavaVM* vm = vmThread->javaVM;
231
U_8* errorBuf;
232
UDATA bufSize;
233
PORT_ACCESS_FROM_JAVAVM(vm);
234
235
Trc_BCU_throwNoClassDefFoundError_Entry(vmThread);
236
237
bufSize = loadData->classNameLength;
238
errorBuf = j9mem_allocate_memory(bufSize + 1, J9MEM_CATEGORY_CLASSES);
239
240
if (errorBuf) {
241
memcpy(errorBuf, loadData->className, bufSize);
242
errorBuf[bufSize] = (U_8) '\0';
243
244
Trc_BCU_throwNoClassDefFoundError_ErrorBuf(vmThread, errorBuf);
245
246
J9_VM_FUNCTION(vmThread, setCurrentExceptionUTF)(vmThread, J9VMCONSTANTPOOL_JAVALANGNOCLASSDEFFOUNDERROR, (char *) errorBuf);
247
248
j9mem_free_memory(errorBuf);
249
} else {
250
J9_VM_FUNCTION(vmThread, setCurrentException)(vmThread, J9VMCONSTANTPOOL_JAVALANGNOCLASSDEFFOUNDERROR, NULL);
251
}
252
253
Trc_BCU_throwNoClassDefFoundError_Exit(vmThread);
254
}
255
256
/*
257
* Check to see if a class with this name is already loaded.
258
* If so, exit the classTableMutex, throw a NoClassDefFoundError (but only if throw-on-fail is set) and return the existing class.
259
* Otherwise return NULL.
260
*/
261
static J9Class*
262
checkForExistingClass(J9VMThread* vmThread, J9LoadROMClassData * loadData)
263
{
264
J9JavaVM* vm = vmThread->javaVM;
265
J9Class* existingClass;
266
267
Trc_BCU_checkForExistingClass_Entry(vmThread, loadData->className, loadData->classLoader);
268
269
existingClass = J9_VM_FUNCTION(vmThread, hashClassTableAt)(
270
loadData->classLoader,
271
loadData->className,
272
loadData->classNameLength);
273
274
if (existingClass != NULL) {
275
/* error! a class with this name is already loaded in this class loader */
276
#ifdef J9VM_THR_PREEMPTIVE
277
omrthread_monitor_exit(vm->classTableMutex);
278
#endif
279
280
Trc_BCU_checkForExistingClass_Exists(vmThread);
281
282
if (loadData->options & J9_FINDCLASS_FLAG_THROW_ON_FAIL) {
283
throwNoClassDefFoundError(vmThread, loadData);
284
}
285
286
Trc_BCU_checkForExistingClass_Exit(vmThread, existingClass);
287
return existingClass;
288
}
289
290
Trc_BCU_checkForExistingClass_Exit(vmThread, NULL);
291
return NULL;
292
}
293
294
static void
295
reportROMClassLoadEvents(J9VMThread* vmThread, J9ROMClass* romClass, J9ClassLoader* classLoader)
296
{
297
J9JavaVM* vm = vmThread->javaVM;
298
299
/*
300
* J9HOOK_ROM_CLASS_LOAD
301
*/
302
TRIGGER_J9HOOK_VM_ROM_CLASS_LOAD(vm->hookInterface, vmThread, romClass);
303
}
304
305
/*
306
* Warning: sender must hold class table mutex before calling.
307
*/
308
UDATA
309
internalLoadROMClass(J9VMThread * vmThread, J9LoadROMClassData *loadData, J9TranslationLocalBuffer *localBuffer)
310
{
311
J9JavaVM * vm = vmThread->javaVM;
312
UDATA result;
313
UDATA translationFlags;
314
UDATA classFileBytesReplacedByRIA = FALSE;
315
UDATA classFileBytesReplacedByRCA = FALSE;
316
U_8 * intermediateClassData = loadData->classData;
317
UDATA intermediateClassDataLength = loadData->classDataLength;
318
void* intermedtiateFreeUserData = NULL;
319
classDataFreeFunction intermediateFreeFunction = NULL;
320
PORT_ACCESS_FROM_VMC(vmThread);
321
322
Trc_BCU_internalLoadROMClass_Entry(vmThread, loadData, loadData->classDataLength);
323
324
#if 0
325
/*This block of code is disabled until CMVC 155494 is resolved. Otherwise it will block cbuilds*/
326
Trc_Assert_BCU_mustHaveVMAccess(vmThread);
327
#endif
328
329
/* Call the class load hook to potentially replace the class data */
330
331
if ((J9_ARE_NO_BITS_SET(loadData->options, J9_FINDCLASS_FLAG_ANON | J9_FINDCLASS_FLAG_HIDDEN) || (J2SE_VERSION(vm) <= J2SE_18))
332
&& (J9_EVENT_IS_HOOKED(vm->hookInterface, J9HOOK_VM_CLASS_LOAD_HOOK) || J9_EVENT_IS_HOOKED(vm->hookInterface, J9HOOK_VM_CLASS_LOAD_HOOK2))
333
) {
334
U_8 * classData = NULL;
335
char * className = NULL;
336
337
Trc_BCU_internalLoadROMClass_ClassLoadHookEnter(vmThread);
338
339
/* If shared cache is BCI enabled and the class is found in shared cache while loading then
340
* loadData->classData points to intermediate ROMClass,
341
* which needs to be converted back to classfile bytes before passing to the agents.
342
*/
343
if (J9_ARE_ALL_BITS_SET(loadData->options, J9_FINDCLASS_FLAG_SHRC_ROMCLASS_EXISTS)) {
344
U_8 * classFileBytes = NULL;
345
U_32 classFileBytesCount = 0;
346
IDATA result = 0;
347
J9ROMClass * intermediateROMClass = (J9ROMClass *) loadData->classData;
348
349
result = j9bcutil_transformROMClass(vm, PORTLIB, intermediateROMClass, &classFileBytes, &classFileBytesCount);
350
if (BCT_ERR_NO_ERROR != result) {
351
Trc_BCU_internalLoadROMClass_ErrorInRecreatingClassfile(vmThread, intermediateROMClass, result);
352
goto done;
353
} else {
354
/* Successfully recreated classfile bytes from intermediate ROMClass. */
355
loadData->classData = classFileBytes;
356
loadData->classDataLength = classFileBytesCount;
357
}
358
} else {
359
result = BCT_ERR_OUT_OF_MEMORY;
360
/* Make a copy of the class data */
361
classData = j9mem_allocate_memory(loadData->classDataLength, J9MEM_CATEGORY_CLASSES);
362
if (classData == NULL) {
363
goto done;
364
}
365
/* If arraylets are in use, the classData will never be an object, it will have been copied before calling internalDefineClass */
366
memcpy(classData, loadData->classData, loadData->classDataLength);
367
if (loadData->freeFunction) {
368
loadData->freeFunction(loadData->freeUserData, loadData->classData);
369
}
370
loadData->classData = classData;
371
}
372
loadData->freeUserData = PORTLIB;
373
loadData->freeFunction = (classDataFreeFunction) OMRPORT_FROM_J9PORT(PORTLIB)->mem_free_memory;
374
loadData->classDataObject = NULL;
375
376
/* Make a copy of the class name */
377
378
if (loadData->classNameLength == 0) {
379
className = NULL;
380
} else {
381
UDATA classNameLength = loadData->classNameLength;
382
if (J9_ARE_ANY_BITS_SET(loadData->options, J9_FINDCLASS_FLAG_ANON | J9_FINDCLASS_FLAG_HIDDEN)) {
383
classNameLength -= (1 + ROM_ADDRESS_LENGTH);
384
}
385
className = j9mem_allocate_memory(classNameLength + 1, J9MEM_CATEGORY_CLASSES);
386
if (className == NULL) {
387
/* free class data before exiting */
388
if (NULL != classData) {
389
j9mem_free_memory(classData);
390
classData = NULL;
391
}
392
goto done;
393
}
394
memcpy(className, loadData->className, classNameLength);
395
className[classNameLength] = '\0';
396
}
397
398
#ifdef J9VM_THR_PREEMPTIVE
399
omrthread_monitor_exit(vm->classTableMutex);
400
#endif
401
402
if ((loadData->options & J9_FINDCLASS_FLAG_RETRANSFORMING) == 0) {
403
ALWAYS_TRIGGER_J9HOOK_VM_CLASS_LOAD_HOOK(vm->hookInterface,
404
vmThread,
405
loadData->classLoader,
406
loadData->protectionDomain,
407
loadData->classBeingRedefined,
408
className,
409
loadData->classData,
410
loadData->classDataLength,
411
loadData->freeUserData,
412
loadData->freeFunction,
413
classFileBytesReplacedByRIA);
414
}
415
416
/* Record the bytes from the above hook call */
417
418
intermediateClassData = loadData->classData;
419
intermediateClassDataLength = loadData->classDataLength;
420
intermedtiateFreeUserData = loadData->freeUserData;
421
intermediateFreeFunction = loadData->freeFunction;
422
loadData->freeFunction = NULL;
423
424
#if defined(J9VM_OPT_JVMTI)
425
426
/* Run the second transformation pass */
427
428
ALWAYS_TRIGGER_J9HOOK_VM_CLASS_LOAD_HOOK2(vm->hookInterface,
429
vmThread,
430
loadData->classLoader,
431
loadData->protectionDomain,
432
loadData->classBeingRedefined,
433
className,
434
loadData->classData,
435
loadData->classDataLength,
436
loadData->freeUserData,
437
loadData->freeFunction,
438
classFileBytesReplacedByRCA);
439
#endif
440
441
#ifdef J9VM_THR_PREEMPTIVE
442
omrthread_monitor_enter(vm->classTableMutex);
443
#endif
444
445
if (className != NULL) {
446
j9mem_free_memory(className);
447
className = NULL;
448
}
449
450
Trc_BCU_internalLoadROMClass_ClassLoadHookDone(vmThread);
451
}
452
453
if (J9_ARE_ALL_BITS_SET(loadData->options, J9_FINDCLASS_FLAG_RETRANSFORMING)
454
&& (FALSE == classFileBytesReplacedByRCA)
455
) {
456
Trc_BCU_Assert_True(FALSE == classFileBytesReplacedByRIA);
457
458
/* Class file is not modified during retransformation.
459
* If active ROMClass->intermediateClassData is a ROMClass then re-use it.
460
*/
461
if (!J9ROMCLASS_IS_INTERMEDIATE_DATA_A_CLASSFILE(loadData->classBeingRedefined->romClass)) {
462
loadData->romClass = (J9ROMClass *) J9ROMCLASS_INTERMEDIATECLASSDATA(loadData->classBeingRedefined->romClass);
463
result = BCT_ERR_NO_ERROR;
464
goto doneFreeMem;
465
}
466
}
467
468
if (0 != (loadData->options & J9_FINDCLASS_FLAG_SHRC_ROMCLASS_EXISTS)) {
469
/* We are running with -Xshareclasses:enableBCI and have already found ROMClass in shared class cache. */
470
if ((FALSE == classFileBytesReplacedByRIA)
471
&& (FALSE == classFileBytesReplacedByRCA)
472
) {
473
/* Either we are using BCI agent which didn't modify the class file data or there is no BCI agent. */
474
Trc_BCU_Assert_NotEquals(NULL, loadData->romClass);
475
result = BCT_ERR_NO_ERROR;
476
goto doneFreeMem;
477
}
478
}
479
480
/* Set up translation flags */
481
482
#ifdef J9VM_ENV_LITTLE_ENDIAN
483
translationFlags = BCT_LittleEndianOutput;
484
#else
485
translationFlags = BCT_BigEndianOutput;
486
#endif
487
488
/*
489
* RECORD_ALL is set by shared classes when it wishes to keep all debug information in the cache
490
* classCouldPossiblyBeShared() returns true when the classloader is a shared classes enabled loader AND the cache is NOT full
491
*
492
* do NOT attempt to strip debug information when RECORD_ALL is set AND the class could end up the cache.
493
*
494
*/
495
if ((J9VM_DEBUG_ATTRIBUTE_RECORD_ALL == (vm->requiredDebugAttributes & J9VM_DEBUG_ATTRIBUTE_RECORD_ALL))
496
&& classCouldPossiblyBeShared(vmThread, loadData)) {
497
/* Shared Classes has requested that all debug information be kept and the class will be shared. */
498
} else if (0 != (vm->runtimeFlags & J9_RUNTIME_XFUTURE)) {
499
/* Don't strip debug information with Xfuture */
500
} else {
501
/* either the class is not going to be shared -or- shared classes does not require the debug information to be maintained */
502
UDATA stripFlags = 0;
503
504
if (0 == (vm->requiredDebugAttributes & J9VM_DEBUG_ATTRIBUTE_LOCAL_VARIABLE_TABLE)) {
505
stripFlags |= BCT_StripDebugVars;
506
}
507
if (0 == (vm->requiredDebugAttributes & J9VM_DEBUG_ATTRIBUTE_LINE_NUMBER_TABLE)) {
508
stripFlags |= BCT_StripDebugLines;
509
}
510
if (0 == (vm->requiredDebugAttributes & J9VM_DEBUG_ATTRIBUTE_SOURCE_FILE)) {
511
stripFlags |= BCT_StripDebugSource;
512
}
513
if (0 == (vm->requiredDebugAttributes & J9VM_DEBUG_ATTRIBUTE_SOURCE_DEBUG_EXTENSION)) {
514
stripFlags |= BCT_StripSourceDebugExtension;
515
}
516
517
if (stripFlags == (BCT_StripDebugVars | BCT_StripDebugLines | BCT_StripDebugSource | BCT_StripSourceDebugExtension)) {
518
stripFlags = BCT_StripDebugAttributes;
519
}
520
translationFlags |= stripFlags;
521
}
522
523
if (J9_ARE_ANY_BITS_SET(vm->runtimeFlags, J9_RUNTIME_VERIFY)) {
524
translationFlags |= BCT_StaticVerification;
525
}
526
527
if (0 != (vm->runtimeFlags & J9_RUNTIME_XFUTURE)) {
528
translationFlags |= BCT_Xfuture;
529
} else {
530
/* Disable static verification for the bootstrap loader if Xfuture not present */
531
if ((vm->systemClassLoader == loadData->classLoader)
532
&& ((NULL == vm->bytecodeVerificationData) || (0 == (vm->bytecodeVerificationData->verificationFlags & J9_VERIFY_BOOTCLASSPATH_STATIC)))
533
&& (NULL == vm->sharedClassConfig)
534
) {
535
translationFlags &= ~BCT_StaticVerification;
536
}
537
}
538
539
if (J9_ARE_ANY_BITS_SET(vm->runtimeFlags, J9_RUNTIME_ALWAYS_SPLIT_BYTECODES)) {
540
translationFlags |= BCT_AlwaysSplitBytecodes;
541
}
542
if (J9_ARE_ANY_BITS_SET(vm->extendedRuntimeFlags2, J9_EXTENDED_RUNTIME2_ENABLE_PREVIEW)) {
543
translationFlags |= BCT_EnablePreview;
544
}
545
/* Determine allowed class file version */
546
#ifdef J9VM_OPT_SIDECAR
547
{
548
/* majorVer is introduced to workaround JDK8 zOS 64bit compiler issue. */
549
U_32 majorVer = BCT_JavaMajorVersionShifted(JAVA_SPEC_VERSION);
550
translationFlags |= majorVer;
551
}
552
#endif
553
554
/* TODO toss tracepoint?? Trc_BCU_internalLoadROMClass_AttemptExisting(vmThread, segment, romAvailable, bytesRequired); */
555
/* Attempt dynamic load */
556
result = callDynamicLoader(vmThread, loadData, intermediateClassData, intermediateClassDataLength, translationFlags, classFileBytesReplacedByRIA, classFileBytesReplacedByRCA, localBuffer);
557
558
/* Free the class file bytes if necessary */
559
doneFreeMem:
560
if (NULL != intermediateFreeFunction) {
561
if (intermediateClassData == loadData->classData) {
562
loadData->freeFunction = NULL;
563
loadData->classData = NULL;
564
}
565
intermediateFreeFunction(intermedtiateFreeUserData, intermediateClassData);
566
intermediateClassData = NULL;
567
}
568
569
if (loadData->freeFunction) {
570
loadData->freeFunction(loadData->freeUserData, loadData->classData);
571
loadData->freeFunction = NULL;
572
loadData->classData = NULL;
573
Trc_BCU_internalLoadROMClass_DoFree(vmThread);
574
}
575
576
/* If the ROM class was created successfully, adjust the heapAlloc of the containing segment */
577
578
done:
579
if (result == BCT_ERR_NO_ERROR) {
580
U_8 *intermediateData = J9ROMCLASS_INTERMEDIATECLASSDATA(loadData->romClass);
581
U_32 intermediateDataSize = loadData->romClass->intermediateClassDataLength;
582
BOOLEAN isSharedClassesEnabled = (NULL != vm->sharedClassConfig);
583
BOOLEAN isSharedClassesBCIEnabled = (TRUE == isSharedClassesEnabled) && (TRUE == vm->sharedClassConfig->isBCIEnabled(vm));
584
585
Trc_BCU_internalLoadROMClass_NoError(vmThread, loadData->romClass);
586
587
/* if romClass is in shared cache, ensure its intermediateClassData also points within shared cache */
588
if ((NULL != intermediateData)
589
&& (TRUE == j9shr_Query_IsAddressInReadWriteCache(vm, loadData->romClass, loadData->romClass->romSize))
590
) {
591
/* romClass and its intermediateData should be in the same cache */
592
Trc_BCU_Assert_True(TRUE == j9shr_Query_IsAddressInReadWriteCache(vm, intermediateData, intermediateDataSize));
593
}
594
595
/* ROMClass should always have intermediate class data. */
596
Trc_BCU_Assert_True(NULL != intermediateData);
597
Trc_BCU_Assert_True(0 != intermediateDataSize);
598
599
/* If retransformation is not allowed and shared cache is not BCI enabled,
600
* or the class file is not modified by RCA then
601
* romClass->intermediateClassData should point to its own ROMClass.
602
*/
603
if ((J9_ARE_NO_BITS_SET(vm->requiredDebugAttributes, J9VM_DEBUG_ATTRIBUTE_ALLOW_RETRANSFORM)
604
&& ((FALSE == isSharedClassesEnabled) || (FALSE == isSharedClassesBCIEnabled)))
605
|| (FALSE == classFileBytesReplacedByRCA)
606
) {
607
Trc_BCU_Assert_True(intermediateData == (U_8 *)loadData->romClass);
608
Trc_BCU_Assert_True(intermediateDataSize == loadData->romClass->romSize);
609
}
610
611
/* If shared cache is BCI enabled and class file is modified then the ROMClass should not be in shared cache. */
612
if ((TRUE == isSharedClassesBCIEnabled)
613
&& ((TRUE == classFileBytesReplacedByRCA)
614
|| (TRUE == classFileBytesReplacedByRIA))
615
) {
616
Trc_BCU_Assert_True(FALSE == j9shr_Query_IsAddressInCache(vm, loadData->romClass, loadData->romClass->romSize));
617
618
/* If class file is modified during load, then intermediate data of the class should not be in shared cache.
619
* But if the class is being re-transformed, then intermediate data may or may not be in shared cache.
620
*/
621
if (J9_ARE_NO_BITS_SET(loadData->options, J9_FINDCLASS_FLAG_RETRANSFORMING)
622
&& (NULL != intermediateData)
623
) {
624
Trc_BCU_Assert_True(FALSE == j9shr_Query_IsAddressInCache(vm, intermediateData, intermediateDataSize));
625
}
626
}
627
} else {
628
loadData->romClass = NULL;
629
loadData->romClassSegment = NULL;
630
}
631
632
#if defined(J9VM_OPT_INVARIANT_INTERNING) && defined(J9VM_OPT_SHARED_CLASSES)
633
if (vm->sharedInvariantInternTable != NULL) {
634
/* This null check is added because a seg fault occurs otherwise. With the /g (code optimization) option enabled,
635
* the following if-statement never gets executed at run-time as it has an empty body. However, since the /g option
636
* is deprecated at Visual Studio 2010 compiler, the following if-statement is now executed at run-time and causes
637
* a seg fault. This is only a temporary workaround, and if necessary, it will be fixed as part of Fatih's work.
638
*/
639
if ((vm->sharedInvariantInternTable->flags & J9AVLTREE_DO_VERIFY_TREE_STRUCT_AND_ACCESS) == J9AVLTREE_DO_VERIFY_TREE_STRUCT_AND_ACCESS) {
640
/* If taking the string table lock fails in SCStoreTransaction, and SCStringTransaction
641
* the local string intern tree may still have been modified. In this case the call to
642
* avl_intern_verify() from the lock enter/exit functions will not have been run, so
643
* the local tree is checked here when the JVM is run with: -Xshareclasses:verifyInternTree
644
*
645
* For example when "-Xshareclasses:readonly" is used entering the string table lock will fail.
646
*/
647
/*TODO:FATIH:verify the table
648
avl_intern_verify(vm->dynamicLoadBuffers->invariantInternTree,
649
vm->dynamicLoadBuffers->invariantInternSharedPool,
650
NULL, FALSE);
651
*/
652
}
653
}
654
#endif
655
656
Trc_BCU_internalLoadROMClass_Exit(vmThread, result);
657
658
return result;
659
}
660
661
static UDATA
662
callDynamicLoader(J9VMThread *vmThread, J9LoadROMClassData *loadData, U_8 * intermediateClassData, UDATA intermediateClassDataLength, UDATA translationFlags, UDATA classFileBytesReplacedByRIA, UDATA classFileBytesReplacedByRCA, J9TranslationLocalBuffer *localBuffer)
663
{
664
J9JavaVM * vm = vmThread->javaVM;
665
BOOLEAN createIntermediateROMClass = FALSE;
666
UDATA result = BCT_ERR_NO_ERROR;
667
U_8 *intermediateData = NULL;
668
UDATA intermediateDataLength = 0;
669
670
/* Pass the verification of stackmaps control flags to be used by static verification (verifyClassFunction - j9bcv_verifyClassStructure) */
671
if (vm->bytecodeVerificationData) {
672
translationFlags |= (vm->bytecodeVerificationData->verificationFlags & (J9_VERIFY_IGNORE_STACK_MAPS | J9_VERIFY_NO_FALLBACK));
673
}
674
675
if (J9_ARE_ANY_BITS_SET(loadData->options, J9_FINDCLASS_FLAG_SHRC_ROMCLASS_EXISTS)) {
676
if (TRUE == classFileBytesReplacedByRCA) {
677
if (FALSE == classFileBytesReplacedByRIA) {
678
/* Intermediate data (either classfile bytes or unmodified J9ROMClass)
679
* is already present in BCI enabled shared cache and
680
* only retransformation capable agent modified the classfile.
681
* In such case existing intermediate data in shared cache can be used
682
* as intermediate data for the new ROMClass.
683
*/
684
intermediateData = J9ROMCLASS_INTERMEDIATECLASSDATA(loadData->romClass);
685
intermediateDataLength = loadData->romClass->intermediateClassDataLength;
686
} else {
687
createIntermediateROMClass = TRUE;
688
}
689
}
690
/* While creating new ROMClass, existing ROMClass should not be passed to ROMClassCreationContext. */
691
loadData->romClass = NULL;
692
} else {
693
if (TRUE == classFileBytesReplacedByRCA) {
694
if (J9_ARE_ANY_BITS_SET(loadData->options, J9_FINDCLASS_FLAG_RETRANSFORMING)) {
695
/* class file bytes are modified during retransformation; use intermediate data from class being redefined */
696
intermediateData = J9ROMCLASS_INTERMEDIATECLASSDATA(loadData->classBeingRedefined->romClass);
697
intermediateDataLength = loadData->classBeingRedefined->romClass->intermediateClassDataLength;
698
} else {
699
createIntermediateROMClass = TRUE;
700
}
701
}
702
}
703
if (TRUE == createIntermediateROMClass) {
704
BOOLEAN useClassfileAsIntermediateData = FALSE;
705
706
if (J9_ARE_ALL_BITS_SET(vm->extendedRuntimeFlags, J9_EXTENDED_RUNTIME_FORCE_CLASSFILE_AS_INTERMEDIATE_DATA)) {
707
useClassfileAsIntermediateData = TRUE;
708
} else {
709
/* Create a ROMClass out of intermediateClassData
710
* and store it as intermediate data in active J9ROMClass.
711
*/
712
J9LoadROMClassData intermediateLoadData;
713
IDATA rc;
714
715
memset(&intermediateLoadData, 0, sizeof(J9LoadROMClassData));
716
intermediateLoadData.classBeingRedefined = NULL;
717
intermediateLoadData.className = loadData->className;
718
intermediateLoadData.classNameLength = loadData->classNameLength;
719
intermediateLoadData.classData = intermediateClassData;
720
intermediateLoadData.classDataLength = intermediateClassDataLength;
721
intermediateLoadData.classLoader = loadData->classLoader;
722
intermediateLoadData.options = loadData->options;
723
/* no need to set other fields in intermediateLoadData */
724
725
rc = j9bcutil_buildRomClass(
726
&intermediateLoadData,
727
NULL, 0, vm,
728
translationFlags,
729
FALSE,
730
TRUE /* isIntermediateROMClass */,
731
localBuffer);
732
733
if (BCT_ERR_NO_ERROR == rc) {
734
intermediateData = (U_8 *)intermediateLoadData.romClass;
735
intermediateDataLength = intermediateLoadData.romClass->romSize;
736
} else {
737
/* Failed to create intermediate ROMClass. Use classfile bytes as intermediate data */
738
Trc_BCU_callDynamicLoader_IntermediateROMClassCreationFailed(loadData, rc);
739
useClassfileAsIntermediateData = TRUE;
740
}
741
}
742
if (TRUE == useClassfileAsIntermediateData) {
743
intermediateData = intermediateClassData;
744
intermediateDataLength = intermediateClassDataLength;
745
translationFlags |= BCT_IntermediateDataIsClassfile;
746
}
747
}
748
749
result = j9bcutil_buildRomClass(
750
loadData,
751
(U_8 *) intermediateData,
752
intermediateDataLength,
753
vm,
754
translationFlags,
755
classFileBytesReplacedByRIA | classFileBytesReplacedByRCA,
756
FALSE, /* isIntermediateROMClass */
757
localBuffer);
758
759
if (BCT_ERR_NO_ERROR == result) {
760
/* The module of a class transformed by a JVMTI agent needs access to unnamed modules */
761
if ((J2SE_VERSION(vm) >= J2SE_V11)
762
&& (classFileBytesReplacedByRIA || classFileBytesReplacedByRCA)
763
) {
764
J9Module *module = J9_VM_FUNCTION(vmThread, findModuleForPackage)(vmThread, loadData->classLoader,
765
J9UTF8_DATA(J9ROMCLASS_CLASSNAME(loadData->romClass)), (U_32) packageNameLength(loadData->romClass));
766
if (NULL != module) {
767
module->isLoose = TRUE;
768
}
769
}
770
771
if (J9_ARE_ANY_BITS_SET(vm->extendedRuntimeFlags, J9_EXTENDED_RUNTIME_RECREATE_CLASSFILE_ONLOAD)) {
772
U_8 * classFileBytes = NULL;
773
U_32 classFileBytesCount = 0;
774
U_8 * prevClassData = loadData->classData;
775
PORT_ACCESS_FROM_JAVAVM(vm);
776
777
/* Use the ROMClass to recreate classfile bytes */
778
result = j9bcutil_transformROMClass(vm, PORTLIB, loadData->romClass, &classFileBytes, &classFileBytesCount);
779
if (BCT_ERR_NO_ERROR == result) {
780
loadData->classData = classFileBytes;
781
loadData->classDataLength = classFileBytesCount;
782
loadData->romClass = NULL;
783
784
result = j9bcutil_buildRomClass(
785
loadData,
786
intermediateData,
787
intermediateDataLength,
788
vm,
789
translationFlags,
790
classFileBytesReplacedByRIA | classFileBytesReplacedByRCA,
791
FALSE, /* isIntermediateROMClass */
792
localBuffer);
793
794
j9mem_free_memory(classFileBytes);
795
}
796
/* Restore classData */
797
loadData->classData = prevClassData;
798
}
799
}
800
return result;
801
}
802
803
static J9ROMClass *
804
createROMClassFromClassFile(J9VMThread *currentThread, J9LoadROMClassData *loadData, J9TranslationLocalBuffer *localBuffer)
805
{
806
J9JavaVM * vm = currentThread->javaVM;
807
UDATA result = 0;
808
U_8 * errorUTF = NULL;
809
UDATA exceptionNumber = J9VMCONSTANTPOOL_JAVALANGCLASSFORMATERROR;
810
void * className = NULL;
811
UDATA classNameLength = 0;
812
J9ClassLoader * classLoader = NULL;
813
814
/* Attempt to create the romClass */
815
816
Trc_BCU_createROMClassFromClassFile_Entry(currentThread, loadData);
817
818
result = internalLoadROMClass(currentThread, loadData, localBuffer);
819
className = loadData->className;
820
classNameLength = loadData->classNameLength;
821
classLoader = loadData->classLoader;
822
823
/* If the romClass was successfully created, continue processing it */
824
825
if (result == BCT_ERR_NO_ERROR) {
826
J9ROMClass * romClass = loadData->romClass;
827
J9UTF8 * romName = J9ROMCLASS_CLASSNAME(romClass);
828
829
/* If a class name was specified, verify that the loaded class has the same name */
830
831
Trc_BCU_createROMClassFromClassFile_postLoadNoErr(currentThread, J9UTF8_LENGTH(romName), J9UTF8_DATA(romName), classLoader, romClass, NULL); /* TODO update trace point*/
832
833
Trc_BCU_createROMClassFromClassFile_Exit(currentThread, romClass);
834
return romClass;
835
}
836
837
/* Always throw load errors */
838
839
Trc_BCU_Assert_True(NULL != vm->dynamicLoadBuffers);
840
841
switch (result) {
842
case BCT_ERR_INVALID_BYTECODE:
843
case BCT_ERR_STACK_MAP_FAILED:
844
case BCT_ERR_VERIFY_ERROR_INLINING:
845
case BCT_ERR_BYTECODE_TRANSLATION_FAILED:
846
case BCT_ERR_UNKNOWN_ANNOTATION:
847
#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)
848
case BCT_ERR_INVALID_VALUE_TYPE:
849
#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */
850
exceptionNumber = J9VMCONSTANTPOOL_JAVALANGVERIFYERROR;
851
break;
852
853
case BCT_ERR_INVALID_ANNOTATION:
854
errorUTF = vm->dynamicLoadBuffers->classFileError;
855
exceptionNumber = J9VMCONSTANTPOOL_JAVALANGVERIFYERROR;
856
break;
857
858
case BCT_ERR_ILLEGAL_PACKAGE_NAME:
859
exceptionNumber = J9VMCONSTANTPOOL_JAVALANGSECURITYEXCEPTION;
860
break;
861
862
case BCT_ERR_OUT_OF_ROM:
863
case BCT_ERR_OUT_OF_MEMORY:
864
exceptionNumber = J9VMCONSTANTPOOL_JAVALANGOUTOFMEMORYERROR;
865
break;
866
867
/*
868
* Error messages are contents of vm->dynamicLoadBuffers->classFileError with class name appended.
869
*
870
* We don't free vm->dynamicLoadBuffers->classFileError because it is also used as a classFileBuffer in ROMClassBuilder.
871
*/
872
case BCT_ERR_CLASS_READ:
873
exceptionNumber = ((J9CfrError *)vm->dynamicLoadBuffers->classFileError)->errorAction;
874
/* FALLTHROUGH */
875
876
case BCT_ERR_GENERIC_ERROR_CUSTOM_MSG: {
877
/* default value for exceptionNumber (J9VMCONSTANTPOOL_JAVALANGCLASSFORMATERROR) assigned before switch */
878
errorUTF = (U_8 *)buildVerifyErrorString(vm, (J9CfrError *)vm->dynamicLoadBuffers->classFileError, className, classNameLength);
879
break;
880
}
881
882
/*
883
* Error messages are contents of vm->dynamicLoadBuffers->classFileError if anything is assigned
884
* otherwise just the classname.
885
*/
886
case BCT_ERR_INVALID_CLASS_TYPE:
887
case BCT_ERR_CLASS_NAME_MISMATCH:
888
exceptionNumber = J9VMCONSTANTPOOL_JAVALANGNOCLASSDEFFOUNDERROR;
889
/* FALLTHROUGH */
890
891
default:
892
/* BCT_ERR_GENERIC_ERROR: default value for exceptionNumber (J9VMCONSTANTPOOL_JAVALANGCLASSFORMATERROR)
893
* assigned before switch */
894
errorUTF = vm->dynamicLoadBuffers->classFileError;
895
if (NULL == errorUTF) {
896
PORT_ACCESS_FROM_JAVAVM(vm);
897
errorUTF = j9mem_allocate_memory(loadData->classNameLength + 1, J9MEM_CATEGORY_CLASSES);
898
if (NULL != errorUTF) {
899
memcpy(errorUTF, loadData->className, loadData->classNameLength);
900
errorUTF[loadData->classNameLength] = (U_8) '\0';
901
}
902
}
903
break;
904
}
905
906
Trc_BCU_Assert_True((NULL == vm->dynamicLoadBuffers->classFileError) || (NULL != errorUTF));
907
vm->dynamicLoadBuffers->classFileError = NULL;
908
909
#ifdef J9VM_THR_PREEMPTIVE
910
omrthread_monitor_exit(vm->classTableMutex);
911
#endif
912
913
Trc_BCU_createROMClassFromClassFile_throwError(currentThread, exceptionNumber);
914
915
/* Do not throw OutOfMemoryError here, instead set the private flags bit */
916
917
if (exceptionNumber == J9VMCONSTANTPOOL_JAVALANGOUTOFMEMORYERROR) {
918
currentThread->privateFlags |= J9_PRIVATE_FLAGS_CLOAD_NO_MEM;
919
/*Trc_BCU_internalLoadROMClass_NoMemory(vmThread);*/
920
} else {
921
if (errorUTF == NULL) {
922
J9_VM_FUNCTION(currentThread, setCurrentException)(currentThread, exceptionNumber, NULL);
923
} else {
924
PORT_ACCESS_FROM_JAVAVM(vm);
925
J9_VM_FUNCTION(currentThread, setCurrentExceptionUTF)(currentThread, exceptionNumber, (const char*)errorUTF);
926
j9mem_free_memory(errorUTF);
927
}
928
}
929
930
Trc_BCU_createROMClassFromClassFile_Exit(currentThread, NULL);
931
return NULL;
932
}
933
934
static UDATA
935
classCouldPossiblyBeShared(J9VMThread * vmThread, J9LoadROMClassData * loadData)
936
{
937
J9JavaVM * vm = vmThread->javaVM;
938
return ((0 != (loadData->classLoader->flags & J9CLASSLOADER_SHARED_CLASSES_ENABLED)) && !j9shr_Query_IsCacheFull(vm));
939
}
940
941
/* Return TRUE if anonClass and hostClass have the same package name.
942
* If anonymous class has no package name, then consider it to be part
943
* of host class's package. Return TRUE if anonymous class has no
944
* package name. Otherwise, return FALSE.
945
*/
946
static BOOLEAN
947
hasSamePackageName(J9ROMClass *anonROMClass, J9ROMClass *hostROMClass) {
948
BOOLEAN rc = FALSE;
949
const UDATA anonClassPackageNameLength = packageNameLength(anonROMClass);
950
951
if (0 == anonClassPackageNameLength) {
952
rc = TRUE;
953
} else {
954
const U_8 *anonClassName = J9UTF8_DATA(J9ROMCLASS_CLASSNAME(anonROMClass));
955
const U_8 *hostClassName = J9UTF8_DATA(J9ROMCLASS_CLASSNAME(hostROMClass));
956
const UDATA hostClassPackageNameLength = packageNameLength(hostROMClass);
957
if (J9UTF8_DATA_EQUALS(anonClassName, anonClassPackageNameLength, hostClassName, hostClassPackageNameLength)) {
958
rc = TRUE;
959
}
960
}
961
962
return rc;
963
}
964
965
/* Create error message with host class and anonymous class. */
966
static char*
967
createErrorMessage(J9VMThread *vmStruct, J9ROMClass *anonROMClass, J9ROMClass *hostROMClass, const char* errorMsg) {
968
PORT_ACCESS_FROM_VMC(vmStruct);
969
char *buf = NULL;
970
971
if (NULL != errorMsg) {
972
UDATA bufLen = 0;
973
const J9UTF8 *anonClassName = J9ROMCLASS_CLASSNAME(anonROMClass);
974
const J9UTF8 *hostClassName = J9ROMCLASS_CLASSNAME(hostROMClass);
975
const U_8 *hostClassNameData = J9UTF8_DATA(hostClassName);
976
const U_8 *anonClassNameData = J9UTF8_DATA(anonClassName);
977
const UDATA hostClassNameLength = J9UTF8_LENGTH(hostClassName);
978
979
/* Anonymous class name has trailing digits. Example - "test/DummyClass/00000000442F098".
980
* The code below removes the trailing digits, "/00000000442F098", from the anonymous class name.
981
*/
982
IDATA anonClassNameLength = J9UTF8_LENGTH(anonClassName) - 1;
983
for (; anonClassNameLength >= 0; anonClassNameLength--) {
984
if (anonClassNameData[anonClassNameLength] == '/') {
985
break;
986
}
987
}
988
989
bufLen = j9str_printf(PORTLIB, NULL, 0, errorMsg,
990
hostClassNameLength, hostClassNameData,
991
anonClassNameLength, anonClassNameData);
992
if (bufLen > 0) {
993
buf = j9mem_allocate_memory(bufLen, OMRMEM_CATEGORY_VM);
994
if (NULL != buf) {
995
j9str_printf(PORTLIB, buf, bufLen, errorMsg,
996
hostClassNameLength, hostClassNameData,
997
anonClassNameLength, anonClassNameData);
998
}
999
}
1000
}
1001
1002
return buf;
1003
}
1004
1005
/* From Java 9 and onwards, set IllegalArgumentException when host class and anonymous class have different packages. */
1006
static void
1007
setIllegalArgumentExceptionHostClassAnonClassHaveDifferentPackages(J9VMThread *vmStruct, J9ROMClass *anonROMClass, J9ROMClass *hostROMClass) {
1008
PORT_ACCESS_FROM_VMC(vmStruct);
1009
const J9JavaVM *vm = vmStruct->javaVM;
1010
1011
/* Construct error string */
1012
const char *errorMsg = j9nls_lookup_message(J9NLS_DO_NOT_PRINT_MESSAGE_TAG | J9NLS_DO_NOT_APPEND_NEWLINE, J9NLS_JCL_HOSTCLASS_ANONCLASS_DIFFERENT_PACKAGES, NULL);
1013
char *buf = createErrorMessage(vmStruct, anonROMClass, hostROMClass, errorMsg);
1014
J9_VM_FUNCTION(vmStruct, setCurrentExceptionUTF)(vmStruct, J9VMCONSTANTPOOL_JAVALANGILLEGALARGUMENTEXCEPTION, buf);
1015
j9mem_free_memory(buf);
1016
}
1017
1018
/* Free the memory segment corresponding to the anonymous ROM class. */
1019
static void
1020
freeAnonROMClass(J9JavaVM *vm, J9ROMClass *romClass) {
1021
if (NULL != romClass) {
1022
omrthread_monitor_t segmentMutex = vm->classMemorySegments->segmentMutex;
1023
omrthread_monitor_enter(segmentMutex);
1024
{
1025
J9MemorySegment **previousSegmentPointerROM = &vm->anonClassLoader->classSegments;
1026
J9MemorySegment *segmentROM = *previousSegmentPointerROM;
1027
BOOLEAN foundMemorySegment = FALSE;
1028
1029
/* Walk all anonymous classloader's ROM memory segments. If ROM class
1030
* is allocated there it would be one per segment.
1031
*/
1032
while (NULL != segmentROM) {
1033
J9MemorySegment *nextSegmentROM = segmentROM->nextSegmentInClassLoader;
1034
if (J9_ARE_ALL_BITS_SET(segmentROM->type, MEMORY_TYPE_ROM_CLASS)
1035
&& ((J9ROMClass *)segmentROM->heapBase == romClass)
1036
) {
1037
foundMemorySegment = TRUE;
1038
/* Found memory segment corresponding to the ROM class. Remove
1039
* this memory segment from the list.
1040
*/
1041
*previousSegmentPointerROM = nextSegmentROM;
1042
/* Free memory segment corresponding to the ROM class. */
1043
J9_VM_FUNCTION_VIA_JAVAVM(vm, freeMemorySegment)(vm, segmentROM, 1);
1044
break;
1045
}
1046
previousSegmentPointerROM = &segmentROM->nextSegmentInClassLoader;
1047
segmentROM = nextSegmentROM;
1048
}
1049
/* Memory segment should always be found if the ROM class exists. */
1050
Trc_BCU_Assert_True(foundMemorySegment);
1051
}
1052
omrthread_monitor_exit(segmentMutex);
1053
}
1054
}
1055
1056
#endif /* J9VM_OPT_DYNAMIC_LOAD_SUPPORT */ /* End File Level Build Flags */
1057
1058