Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/gc_base/ClassLoaderManager.cpp
5986 views
1
2
/*******************************************************************************
3
* Copyright (c) 1991, 2021 IBM Corp. and others
4
*
5
* This program and the accompanying materials are made available under
6
* the terms of the Eclipse Public License 2.0 which accompanies this
7
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
8
* or the Apache License, Version 2.0 which accompanies this distribution and
9
* is available at https://www.apache.org/licenses/LICENSE-2.0.
10
*
11
* This Source Code may also be made available under the following
12
* Secondary Licenses when the conditions for such availability set
13
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
14
* General Public License, version 2 with the GNU Classpath
15
* Exception [1] and GNU General Public License, version 2 with the
16
* OpenJDK Assembly Exception [2].
17
*
18
* [1] https://www.gnu.org/software/classpath/license.html
19
* [2] http://openjdk.java.net/legal/assembly-exception.html
20
*
21
* 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
22
*******************************************************************************/
23
24
#include "j9.h"
25
#include "j9cfg.h"
26
#include "j9protos.h"
27
#include "j9consts.h"
28
#include "segment.h"
29
#include "ModronAssertions.h"
30
#include "vmhook_internal.h" /* this file triggers a VM hook, so we need the internal version */
31
32
#include "ClassLoaderManager.hpp"
33
34
#include "ClassHeapIterator.hpp"
35
#include "ClassLoaderIterator.hpp"
36
#include "ClassLoaderSegmentIterator.hpp"
37
#include "ClassUnloadStats.hpp"
38
#include "EnvironmentBase.hpp"
39
#include "FinalizableClassLoaderBuffer.hpp"
40
#include "GCExtensions.hpp"
41
#include "GlobalCollector.hpp"
42
#include "HeapMap.hpp"
43
#include "ClassLoaderRememberedSet.hpp"
44
45
#if defined(J9VM_GC_REALTIME)
46
extern "C" {
47
void classLoaderLoadHook(J9HookInterface** hook, UDATA eventNum, void* eventData, void* userData);
48
}
49
#endif /* defined(J9VM_GC_REALTIME) */
50
51
MM_ClassLoaderManager *
52
MM_ClassLoaderManager::newInstance(MM_EnvironmentBase *env, MM_GlobalCollector *globalCollector)
53
{
54
MM_ClassLoaderManager *classLoaderManager = (MM_ClassLoaderManager *)env->getForge()->allocate(sizeof(MM_ClassLoaderManager), MM_AllocationCategory::FIXED, J9_GET_CALLSITE());
55
if (classLoaderManager) {
56
new(classLoaderManager) MM_ClassLoaderManager(env, globalCollector);
57
if (!classLoaderManager->initialize(env)) {
58
classLoaderManager->kill(env);
59
classLoaderManager = NULL;
60
}
61
}
62
return classLoaderManager;
63
}
64
65
void
66
MM_ClassLoaderManager::kill(MM_EnvironmentBase *env)
67
{
68
tearDown(env);
69
env->getForge()->free(this);
70
}
71
72
void
73
MM_ClassLoaderManager::tearDown(MM_EnvironmentBase *env)
74
{
75
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
76
if (_undeadSegmentListMonitor) {
77
omrthread_monitor_destroy(_undeadSegmentListMonitor);
78
_undeadSegmentListMonitor = NULL;
79
}
80
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
81
82
if (_classLoaderListMonitor) {
83
omrthread_monitor_destroy(_classLoaderListMonitor);
84
_classLoaderListMonitor = NULL;
85
}
86
87
#if defined(J9VM_GC_REALTIME)
88
if (MM_GCExtensions::getExtensions(env)->isMetronomeGC()) {
89
J9HookInterface **vmHookInterface = _javaVM->internalVMFunctions->getVMHookInterface(_javaVM);
90
if (NULL != vmHookInterface) {
91
(*vmHookInterface)->J9HookUnregister(vmHookInterface, J9HOOK_VM_CLASS_LOADER_INITIALIZED, classLoaderLoadHook, this);
92
}
93
}
94
#endif /* defined(J9VM_GC_REALTIME) */
95
}
96
97
/**
98
* Initialize the class unload manager structure. This just means that the monitor and the pointers are initialized.
99
*
100
* @return true if the initialization was successful, false otherwise.
101
*/
102
bool
103
MM_ClassLoaderManager::initialize(MM_EnvironmentBase *env)
104
{
105
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
106
_firstUndeadSegment = NULL;
107
_undeadSegmentsTotalSize = 0;
108
109
if (0 != omrthread_monitor_init_with_name(&_undeadSegmentListMonitor, 0, "Undead Segment List Monitor")) {
110
return false;
111
}
112
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
113
114
if (0 != omrthread_monitor_init_with_name(&_classLoaderListMonitor, 0, "Class Loader List Monitor")) {
115
return false;
116
}
117
118
J9HookInterface **vmHookInterface = _javaVM->internalVMFunctions->getVMHookInterface(_javaVM);
119
if (NULL == vmHookInterface) {
120
return false;
121
}
122
123
#if defined(J9VM_GC_REALTIME)
124
/* TODO CRGTMP Remove if once non-realtime collectors use classLoaderManager during
125
* unloadDeadClassLoaders. This was added to fix CMVC 127599 until stability week is over
126
*/
127
if (MM_GCExtensions::getExtensions(env)->isMetronomeGC()) {
128
if ((*vmHookInterface)->J9HookRegisterWithCallSite(vmHookInterface, J9HOOK_VM_CLASS_LOADER_INITIALIZED, classLoaderLoadHook, OMR_GET_CALLSITE(), this)) {
129
return false;
130
}
131
}
132
#endif /* defined(J9VM_GC_REALTIME) */
133
134
return true;
135
}
136
137
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
138
void
139
MM_ClassLoaderManager::enqueueUndeadClassSegments(J9MemorySegment *listRoot)
140
{
141
if (NULL != listRoot) {
142
omrthread_monitor_enter(_undeadSegmentListMonitor);
143
144
while (NULL != listRoot) {
145
_undeadSegmentsTotalSize += listRoot->size;
146
J9MemorySegment *nextSegment = listRoot->nextSegmentInClassLoader;
147
listRoot->nextSegmentInClassLoader = _firstUndeadSegment;
148
_firstUndeadSegment = listRoot;
149
listRoot = nextSegment;
150
}
151
omrthread_monitor_exit(_undeadSegmentListMonitor);
152
}
153
}
154
155
void
156
MM_ClassLoaderManager::flushUndeadSegments(MM_EnvironmentBase *env)
157
{
158
omrthread_monitor_enter(_undeadSegmentListMonitor);
159
/* now free all the segments */
160
J9MemorySegment *walker = _firstUndeadSegment;
161
_firstUndeadSegment = NULL;
162
_undeadSegmentsTotalSize = 0;
163
omrthread_monitor_exit(_undeadSegmentListMonitor);
164
165
while (NULL != walker) {
166
J9MemorySegment *thisWalk = walker;
167
walker = thisWalk->nextSegmentInClassLoader;
168
_javaVM->internalVMFunctions->freeMemorySegment(_javaVM, thisWalk, TRUE);
169
_globalCollector->condYield(env, 0);
170
}
171
}
172
173
void
174
MM_ClassLoaderManager::setLastUnloadNumOfClassLoaders()
175
{
176
_lastUnloadNumOfClassLoaders = (UDATA)pool_numElements(_javaVM->classLoaderBlocks);
177
}
178
179
void
180
MM_ClassLoaderManager::setLastUnloadNumOfAnonymousClasses()
181
{
182
_lastUnloadNumOfAnonymousClasses = _javaVM->anonClassCount;
183
}
184
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
185
186
void
187
MM_ClassLoaderManager::unlinkClassLoader(J9ClassLoader *classLoader)
188
{
189
omrthread_monitor_enter(_classLoaderListMonitor);
190
J9_LINEAR_LINKED_LIST_REMOVE(gcLinkNext, gcLinkPrevious, _classLoaders, classLoader);
191
omrthread_monitor_exit(_classLoaderListMonitor);
192
193
}
194
195
void
196
MM_ClassLoaderManager::linkClassLoader(J9ClassLoader *classLoader)
197
{
198
omrthread_monitor_enter(_classLoaderListMonitor);
199
J9_LINEAR_LINKED_LIST_ADD(gcLinkNext, gcLinkPrevious, _classLoaders, classLoader);
200
omrthread_monitor_exit(_classLoaderListMonitor);
201
}
202
203
bool
204
MM_ClassLoaderManager::isTimeForClassUnloading(MM_EnvironmentBase *env)
205
{
206
bool result = false;
207
208
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
209
210
UDATA numClassLoaderBlocks = pool_numElements(_javaVM->classLoaderBlocks);
211
UDATA numAnonymousClasses = _javaVM->anonClassCount;
212
213
Trc_MM_GlobalCollector_isTimeForClassUnloading_Entry(
214
_extensions->dynamicClassUnloading,
215
numClassLoaderBlocks,
216
_extensions->dynamicClassUnloadingThreshold,
217
_lastUnloadNumOfClassLoaders
218
);
219
220
Trc_MM_GlobalCollector_isTimeForClassUnloading_anonClasses(
221
numAnonymousClasses,
222
_lastUnloadNumOfAnonymousClasses,
223
_extensions->classUnloadingAnonymousClassWeight
224
);
225
226
Assert_MM_true(numAnonymousClasses >= _lastUnloadNumOfAnonymousClasses);
227
228
if ( _extensions->dynamicClassUnloading != MM_GCExtensions::DYNAMIC_CLASS_UNLOADING_NEVER ) {
229
UDATA recentlyLoaded = (UDATA) ((numAnonymousClasses - _lastUnloadNumOfAnonymousClasses) * _extensions->classUnloadingAnonymousClassWeight);
230
/* todo aryoung: _lastUnloadNumOfClassLoaders includes the class loaders which
231
* were unloaded but still required finalization when the last classUnloading occured.
232
* This means that the threshold check is wrong when there are classes which require finalization.
233
* Temporarily make sure that we do not create a negative recently loaded.
234
*/
235
if (numClassLoaderBlocks >= _lastUnloadNumOfClassLoaders) {
236
recentlyLoaded += (numClassLoaderBlocks - _lastUnloadNumOfClassLoaders);
237
}
238
result = recentlyLoaded >= _extensions->dynamicClassUnloadingThreshold;
239
}
240
241
Trc_MM_GlobalCollector_isTimeForClassUnloading_Exit(result ? "true" : "false");
242
243
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
244
return result;
245
}
246
247
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
248
J9ClassLoader *
249
MM_ClassLoaderManager::identifyClassLoadersToUnload(MM_EnvironmentBase *env, MM_HeapMap *markMap, MM_ClassUnloadStats* classUnloadStats)
250
{
251
Trc_MM_identifyClassLoadersToUnload_Entry(env->getLanguageVMThread());
252
253
Assert_MM_true(NULL != markMap);
254
J9ClassLoader *unloadLink = NULL;
255
classUnloadStats->_classLoaderCandidates = 0;
256
257
GC_ClassLoaderIterator classLoaderIterator(_javaVM->classLoaderBlocks);
258
J9ClassLoader * classLoader = NULL;
259
while( NULL != (classLoader = classLoaderIterator.nextSlot()) ) {
260
classUnloadStats->_classLoaderCandidates += 1;
261
/* Check if the class loader is already DEAD - ignore if it is */
262
if( J9_GC_CLASS_LOADER_DEAD == (classLoader->gcFlags & J9_GC_CLASS_LOADER_DEAD) ) {
263
/* If the class loader is already dead, it should be enqueued or unloading by now */
264
Assert_MM_true( 0 != (classLoader->gcFlags & (J9_GC_CLASS_LOADER_UNLOADING | J9_GC_CLASS_LOADER_ENQ_UNLOAD)) );
265
Assert_MM_true( 0 == (classLoader->gcFlags & J9_GC_CLASS_LOADER_SCANNED) );
266
} else {
267
/* If the class loader isn't already dead, it must not be enqueued or unloading */
268
Assert_MM_true( 0 == (classLoader->gcFlags & (J9_GC_CLASS_LOADER_UNLOADING | J9_GC_CLASS_LOADER_ENQ_UNLOAD)) );
269
Assert_MM_true(NULL == classLoader->unloadLink);
270
271
/* Is the class loader still alive? (object may be NULL while the loader is being initialized) */
272
J9Object *classLoaderObject = classLoader->classLoaderObject;
273
if( (NULL != classLoaderObject) && (!markMap->isBitSet(classLoaderObject)) ) {
274
/* Anonymous classloader should not be unloaded */
275
Assert_MM_true(0 == (classLoader->flags & J9CLASSLOADER_ANON_CLASS_LOADER));
276
Assert_MM_true( 0 == (classLoader->gcFlags & J9_GC_CLASS_LOADER_SCANNED) );
277
278
/* add this loader to the linked list of loaders being unloaded in this cycle */
279
classLoader->unloadLink = unloadLink;
280
unloadLink = classLoader;
281
} else {
282
if (MM_GCExtensions::getExtensions(env)->isVLHGC()) {
283
/* we don't use the SCANNED flag in VLHGC */
284
Assert_MM_true(0 == (classLoader->gcFlags & J9_GC_CLASS_LOADER_SCANNED));
285
} else {
286
/* TODO: Once SE stops using the SCANNED flag this path can be removed */
287
/* Anonymous classloader might not have SCANNED flag set */
288
if (0 == (classLoader->flags & J9CLASSLOADER_ANON_CLASS_LOADER)) {
289
Assert_MM_true(J9_GC_CLASS_LOADER_SCANNED == (classLoader->gcFlags & J9_GC_CLASS_LOADER_SCANNED));
290
}
291
classLoader->gcFlags &= ~J9_GC_CLASS_LOADER_SCANNED;
292
}
293
}
294
}
295
}
296
297
Trc_MM_identifyClassLoadersToUnload_Exit(env->getLanguageVMThread());
298
299
return unloadLink;
300
}
301
302
void
303
MM_ClassLoaderManager::cleanUpClassLoadersStart(MM_EnvironmentBase *env, J9ClassLoader* classLoaderUnloadList, MM_HeapMap *markMap, MM_ClassUnloadStats *classUnloadStats)
304
{
305
UDATA classUnloadCount = 0;
306
UDATA anonymousClassUnloadCount = 0;
307
UDATA classLoaderUnloadCount = 0;
308
J9VMThread *vmThread = (J9VMThread *)env->getLanguageVMThread();
309
310
J9Class *classUnloadList = NULL;
311
J9Class *anonymousClassUnloadList = NULL;
312
313
Trc_MM_cleanUpClassLoadersStart_Entry(env->getLanguageVMThread());
314
315
/*
316
* Verify that boolean array class has been marked. Assertion is done to ensure correctness
317
* of an optimization in ClassIteratorClassSlots that only checks booleanArrayClass Interfaces
318
* since all array claseses share the same ITable.
319
*/
320
Assert_MM_true(markMap->isBitSet(_javaVM->booleanArrayClass->classObject));
321
322
/*
323
* Walk anonymous classes and set unmarked as dying
324
*
325
* Do this walk before classloaders to be unloaded walk to create list of anonymous classes to be unloaded and use it
326
* as sublist to continue to build general list of classes to be unloaded
327
*
328
* Anonymous classes suppose to be allocated one per segment
329
* This is not relevant here however becomes important at segment removal time
330
*/
331
anonymousClassUnloadList = addDyingClassesToList(env, _javaVM->anonClassLoader, markMap, false, anonymousClassUnloadList, &anonymousClassUnloadCount);
332
333
/* class unload list includes anonymous class unload list */
334
classUnloadList = anonymousClassUnloadList;
335
classUnloadCount += anonymousClassUnloadCount;
336
337
/* Count all classes loaded by dying class loaders */
338
J9ClassLoader * classLoader = classLoaderUnloadList;
339
while (NULL != classLoader) {
340
Assert_MM_true( 0 == (classLoader->gcFlags & J9_GC_CLASS_LOADER_SCANNED) );
341
classLoaderUnloadCount += 1;
342
classLoader->gcFlags |= J9_GC_CLASS_LOADER_DEAD;
343
344
/* mark all of its classes as dying */
345
classUnloadList = addDyingClassesToList(env, classLoader, markMap, true, classUnloadList, &classUnloadCount);
346
347
classLoader = classLoader->unloadLink;
348
}
349
350
if (0 != classUnloadCount) {
351
/* Call classes unload hook */
352
Trc_MM_cleanUpClassLoadersStart_triggerClassesUnload(env->getLanguageVMThread(), classUnloadCount);
353
TRIGGER_J9HOOK_VM_CLASSES_UNLOAD(_javaVM->hookInterface, vmThread, classUnloadCount, classUnloadList);
354
}
355
356
if (0 != anonymousClassUnloadCount) {
357
/* Call anonymous classes unload hook */
358
Trc_MM_cleanUpClassLoadersStart_triggerAnonymousClassesUnload(env->getLanguageVMThread(), anonymousClassUnloadCount);
359
TRIGGER_J9HOOK_VM_ANON_CLASSES_UNLOAD(_javaVM->hookInterface, vmThread, anonymousClassUnloadCount, anonymousClassUnloadList);
360
}
361
362
if (0 != classLoaderUnloadCount) {
363
/* Call classloader unload hook */
364
Trc_MM_cleanUpClassLoadersStart_triggerClassLoadersUnload(env->getLanguageVMThread(), classLoaderUnloadCount);
365
TRIGGER_J9HOOK_VM_CLASS_LOADERS_UNLOAD(_javaVM->hookInterface, vmThread, classLoaderUnloadList);
366
}
367
368
classUnloadStats->_classesUnloadedCount = classUnloadCount;
369
classUnloadStats->_classLoaderUnloadedCount = classLoaderUnloadCount;
370
classUnloadStats->_anonymousClassesUnloadedCount = anonymousClassUnloadCount;
371
372
/* Ensure that the vm has an accurate number of currently loaded anonymous classes */
373
_javaVM->anonClassCount -= anonymousClassUnloadCount;
374
375
Trc_MM_cleanUpClassLoadersStart_Exit(env->getLanguageVMThread());
376
}
377
378
J9Class *
379
MM_ClassLoaderManager::addDyingClassesToList(MM_EnvironmentBase *env, J9ClassLoader * classLoader, MM_HeapMap *markMap, bool setAll, J9Class *classUnloadListStart, UDATA *classUnloadCountResult)
380
{
381
J9VMThread *vmThread = (J9VMThread *)env->getLanguageVMThread();
382
J9Class *classUnloadList = classUnloadListStart;
383
UDATA classUnloadCount = 0;
384
385
if (NULL != classLoader) {
386
GC_ClassLoaderSegmentIterator segmentIterator(classLoader, MEMORY_TYPE_RAM_CLASS);
387
J9MemorySegment *segment = NULL;
388
while(NULL != (segment = segmentIterator.nextSegment())) {
389
GC_ClassHeapIterator classHeapIterator(_javaVM, segment);
390
J9Class *clazz = NULL;
391
while(NULL != (clazz = classHeapIterator.nextClass())) {
392
J9Object *classObject = clazz->classObject;
393
if (setAll || !markMap->isBitSet(classObject)) {
394
395
/* with setAll all classes must be unmarked */
396
Assert_MM_true(!markMap->isBitSet(classObject));
397
398
classUnloadCount += 1;
399
400
/* Remove the class from the subclass traversal list */
401
removeFromSubclassHierarchy(env, clazz);
402
403
/* Mark class as dying */
404
clazz->classDepthAndFlags |= J9AccClassDying;
405
406
/* For CMVC 137275. For all dying classes we poison the classObject
407
* field to J9_INVALID_OBJECT to investigate the origin of a class object
408
* reference whose class has been unloaded.
409
*/
410
clazz->classObject = (j9object_t) J9_INVALID_OBJECT;
411
412
/* Call class unload hook */
413
Trc_MM_cleanUpClassLoadersStart_triggerClassUnload(env->getLanguageVMThread(),clazz,
414
(UDATA) J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(clazz->romClass)),
415
J9UTF8_DATA(J9ROMCLASS_CLASSNAME(clazz->romClass)));
416
TRIGGER_J9HOOK_VM_CLASS_UNLOAD(_javaVM->hookInterface, vmThread, clazz);
417
418
/* add class to dying classes link list */
419
clazz->gcLink = classUnloadList;
420
classUnloadList = clazz;
421
}
422
}
423
}
424
}
425
426
*classUnloadCountResult += classUnloadCount;
427
return classUnloadList;
428
}
429
430
void
431
MM_ClassLoaderManager::cleanUpClassLoadersEnd(MM_EnvironmentBase *env, J9ClassLoader* unloadLink)
432
{
433
J9VMThread *vmThread = (J9VMThread *)env->getLanguageVMThread();
434
J9MemorySegment *reclaimedSegments = NULL;
435
436
Trc_MM_cleanUpClassLoadersEnd_Entry(vmThread);
437
438
/* Unload classes in the unload link and pass back any RAM Classes that we encounter so the caller can decide when to free them */
439
Trc_MM_cleanUpClassLoadersEnd_deleteDeadClassLoaderClassSegmentsStart(env->getLanguageVMThread());
440
Trc_MM_cleanUpClassLoadersEnd_unloadClassLoadersNotRequiringFinalizerStart(env->getLanguageVMThread());
441
while (NULL != unloadLink) {
442
J9ClassLoader *nextUnloadLink = unloadLink->unloadLink;
443
J9MemorySegment *segment = unloadLink->classSegments;
444
/* now clean up all the segments for this class loader */
445
cleanUpSegmentsAlongClassLoaderLink(_javaVM, segment, &reclaimedSegments);
446
_javaVM->internalVMFunctions->freeClassLoader(unloadLink, _javaVM, vmThread, 1);
447
unloadLink = nextUnloadLink;
448
}
449
450
/* we should have already cleaned up the segments attached to this class so it should return none reclaimed */
451
Assert_MM_true(NULL == reclaimedSegments);
452
453
Trc_MM_cleanUpClassLoadersEnd_Exit(env->getLanguageVMThread());
454
}
455
456
void
457
MM_ClassLoaderManager::cleanUpSegmentsAlongClassLoaderLink(J9JavaVM *javaVM, J9MemorySegment *segment, J9MemorySegment **reclaimedSegments)
458
{
459
while (NULL != segment) {
460
J9MemorySegment *nextSegment = segment->nextSegmentInClassLoader;
461
if (segment->type & MEMORY_TYPE_RAM_CLASS) {
462
segment->type |= MEMORY_TYPE_UNDEAD_CLASS;
463
/* we also need to unset the fact that this is a RAM CLASS since some code which walks the segment list is looking for still-valid ones */
464
segment->type &= ~MEMORY_TYPE_RAM_CLASS;
465
segment->nextSegmentInClassLoader = *reclaimedSegments;
466
*reclaimedSegments = segment;
467
segment->classLoader = NULL;
468
} else if (!(segment->type & MEMORY_TYPE_UNDEAD_CLASS)) {
469
javaVM->internalVMFunctions->freeMemorySegment(javaVM, segment, 1);
470
}
471
segment = nextSegment;
472
}
473
}
474
475
void
476
MM_ClassLoaderManager::cleanUpSegmentsInAnonymousClassLoader(MM_EnvironmentBase *env, J9MemorySegment **reclaimedSegments)
477
{
478
if (NULL != _javaVM->anonClassLoader) {
479
J9MemorySegment **previousSegmentPointer = &_javaVM->anonClassLoader->classSegments;
480
J9MemorySegment *segment = *previousSegmentPointer;
481
482
while (NULL != segment) {
483
J9MemorySegment *nextSegment = segment->nextSegmentInClassLoader;
484
bool removed = false;
485
if (MEMORY_TYPE_RAM_CLASS == (segment->type & MEMORY_TYPE_RAM_CLASS)) {
486
GC_ClassHeapIterator classHeapIterator(_javaVM, segment);
487
/* Get anonymous class from this segment */
488
J9Class *clazz = classHeapIterator.nextClass();
489
/* Anonymous classes expected to be allocated one per segment */
490
Assert_MM_true(NULL == classHeapIterator.nextClass());
491
492
if (J9AccClassDying == (J9CLASS_FLAGS(clazz) & J9AccClassDying)) {
493
/* TODO replace this to better algorithm */
494
/* Try to find ROM class for unloading anonymous RAM class if it is not an array */
495
if (!_extensions->objectModel.isIndexable(clazz)) {
496
J9ROMClass *romClass = clazz->romClass;
497
if (NULL != romClass) {
498
J9MemorySegment **previousSegmentPointerROM = &_javaVM->anonClassLoader->classSegments;
499
J9MemorySegment *segmentROM = *previousSegmentPointerROM;
500
501
/*
502
* Walk all anonymous classloader's ROM memory segments
503
* If ROM class is allocated there it would be one per segment
504
*/
505
while (NULL != segmentROM) {
506
J9MemorySegment *nextSegmentROM = segmentROM->nextSegmentInClassLoader;
507
if ((MEMORY_TYPE_ROM_CLASS == (segmentROM->type & MEMORY_TYPE_ROM_CLASS)) && ((J9ROMClass *)segmentROM->heapBase == romClass)) {
508
/* found! */
509
/* remove memory segment from list */
510
*previousSegmentPointerROM = nextSegmentROM;
511
/* correct pre-cached next for RAM iteration cycle if necessary */
512
if (nextSegment == segmentROM) {
513
nextSegment = nextSegmentROM;
514
}
515
/* correct pre-cached previous for RAM iteration cycle if necessary */
516
if (segmentROM->nextSegmentInClassLoader == segment) {
517
previousSegmentPointer = previousSegmentPointerROM;
518
}
519
/* ...and free memory segment */
520
_javaVM->internalVMFunctions->freeMemorySegment(_javaVM, segmentROM, 1);
521
break;
522
}
523
previousSegmentPointerROM = &segmentROM->nextSegmentInClassLoader;
524
segmentROM = nextSegmentROM;
525
}
526
}
527
}
528
529
segment->type |= MEMORY_TYPE_UNDEAD_CLASS;
530
/* we also need to unset the fact that this is a RAM CLASS since some code which walks the segment list is looking for still-valid ones */
531
segment->type &= ~MEMORY_TYPE_RAM_CLASS;
532
segment->nextSegmentInClassLoader = *reclaimedSegments;
533
*reclaimedSegments = segment;
534
segment->classLoader = NULL;
535
/* remove RAM memory segment from classloader segments list */
536
*previousSegmentPointer = nextSegment;
537
removed = true;
538
}
539
}
540
if (!removed) {
541
previousSegmentPointer = &segment->nextSegmentInClassLoader;
542
}
543
segment = nextSegment;
544
}
545
}
546
}
547
548
void
549
MM_ClassLoaderManager::removeFromSubclassHierarchy(MM_EnvironmentBase *env, J9Class *clazzPtr)
550
{
551
J9Class* nextLink = clazzPtr->subclassTraversalLink;
552
J9Class* reverseLink = clazzPtr->subclassTraversalReverseLink;
553
554
reverseLink->subclassTraversalLink = nextLink;
555
nextLink->subclassTraversalReverseLink = reverseLink;
556
557
/* link this obsolete class to itself so that it won't have dangling pointers into the subclass traversal list */
558
clazzPtr->subclassTraversalLink = clazzPtr;
559
clazzPtr->subclassTraversalReverseLink = clazzPtr;
560
}
561
562
void
563
MM_ClassLoaderManager::cleanUpClassLoaders(MM_EnvironmentBase *env, J9ClassLoader *classLoadersUnloadedList, J9MemorySegment** reclaimedSegments, J9ClassLoader ** unloadLink, volatile bool* finalizationRequired)
564
{
565
*reclaimedSegments = NULL;
566
*unloadLink = NULL;
567
568
/*
569
* Cleanup segments in anonymous classloader
570
*/
571
cleanUpSegmentsInAnonymousClassLoader(env, reclaimedSegments);
572
573
/* For each classLoader that is not already unloading, not scanned and not enqueued for finalization:
574
* perform classLoader-specific clean up, if it died on the current collection cycle; and either enqueue it for
575
* finalization, if it needs any shared libraries to be unloaded, or add it to the list of classLoaders to be
576
* unloaded by cleanUpClassLoadersEnd.
577
*/
578
GC_FinalizableClassLoaderBuffer buffer(_extensions);
579
while (NULL != classLoadersUnloadedList) {
580
/* fetch the next loader immediately, since we will re-use the unloadLink in this loop */
581
J9ClassLoader* classLoader = classLoadersUnloadedList;
582
classLoadersUnloadedList = classLoader->unloadLink;
583
584
Assert_MM_true(0 == (classLoader->gcFlags & J9_GC_CLASS_LOADER_SCANNED)); /* we don't use the SCANNED flag in VLHGC */
585
Assert_MM_true(J9_GC_CLASS_LOADER_DEAD == (classLoader->gcFlags & J9_GC_CLASS_LOADER_DEAD));
586
Assert_MM_true(0 == (classLoader->gcFlags & (J9_GC_CLASS_LOADER_UNLOADING | J9_GC_CLASS_LOADER_ENQ_UNLOAD)));
587
588
Trc_MM_ClassLoaderUnload(env->getLanguageVMThread());
589
590
/* Perform classLoader-specific clean up work, including freeing the classLoader's class hash table and
591
* class path entries.
592
*/
593
_javaVM->internalVMFunctions->cleanUpClassLoader((J9VMThread *)env->getLanguageVMThread(), classLoader);
594
595
#if defined(J9VM_GC_FINALIZATION)
596
/* Determine if the classLoader needs to be enqueued for finalization (for shared library unloading),
597
* otherwise add it to the list of classLoaders to be unloaded by cleanUpClassLoadersEnd.
598
*/
599
if(((NULL != classLoader->sharedLibraries)
600
&& (0 != pool_numElements(classLoader->sharedLibraries)))
601
|| (_extensions->fvtest_forceFinalizeClassLoaders)) {
602
/* Enqueue the class loader for the finalizer */
603
buffer.add(env, classLoader);
604
classLoader->gcFlags |= J9_GC_CLASS_LOADER_ENQ_UNLOAD;
605
*finalizationRequired = true;
606
} else {
607
/* Add the classLoader to the list of classLoaders to be unloaded by cleanUpClassLoadersEnd */
608
classLoader->unloadLink = *unloadLink;
609
*unloadLink = classLoader;
610
}
611
#endif /* J9VM_GC_FINALIZATION */
612
613
/* free any ROM classes now and enqueue any RAM classes */
614
cleanUpSegmentsAlongClassLoaderLink(_javaVM, classLoader->classSegments, reclaimedSegments);
615
616
/* we are taking responsibility for cleaning these here so free them */
617
classLoader->classSegments = NULL;
618
619
/* perform any configuration specific clean up */
620
if (_extensions->isVLHGC()) {
621
MM_ClassLoaderRememberedSet *classLoaderRememberedSet = _extensions->classLoaderRememberedSet;
622
if (MM_CycleState::CT_PARTIAL_GARBAGE_COLLECTION == env->_cycleState->_collectionType) {
623
/* during PGCs we should never unload a class loader which is remembered because it could have instances */
624
Assert_MM_false(classLoaderRememberedSet->isRemembered(env, classLoader));
625
}
626
classLoaderRememberedSet->killRememberedSet(env, classLoader);
627
}
628
}
629
buffer.flush(env);
630
}
631
632
bool
633
MM_ClassLoaderManager::tryEnterClassUnloadMutex(MM_EnvironmentBase *env)
634
{
635
bool result = true;
636
637
/* now, perform any actions that the global collector needs to take before a collection starts */
638
#if defined(J9VM_JIT_CLASS_UNLOAD_RWMONITOR)
639
if (0 != omrthread_rwmutex_try_enter_write(_javaVM->classUnloadMutex))
640
#else
641
if (0 != omrthread_monitor_try_enter(_javaVM->classUnloadMutex))
642
#endif /* J9VM_JIT_CLASS_UNLOAD_RWMONITOR */
643
{
644
/* The JIT currently is in the monitor */
645
/* We can simply skip unloading classes for this GC */
646
result = false;
647
}
648
return result;
649
}
650
651
U_64
652
MM_ClassLoaderManager::enterClassUnloadMutex(MM_EnvironmentBase *env)
653
{
654
PORT_ACCESS_FROM_ENVIRONMENT(env);
655
U_64 quiesceTime = J9CONST64(0);
656
657
/* now, perform any actions that the global collector needs to take before a collection starts */
658
#if defined(J9VM_JIT_CLASS_UNLOAD_RWMONITOR)
659
if (0 != omrthread_rwmutex_try_enter_write(_javaVM->classUnloadMutex))
660
#else
661
if (0 != omrthread_monitor_try_enter(_javaVM->classUnloadMutex))
662
#endif /* J9VM_JIT_CLASS_UNLOAD_RWMONITOR */
663
{
664
/* The JIT currently is in the monitor */
665
/* We must interrupt the JIT compilation so the GC can unload classes */
666
U_64 startTime = j9time_hires_clock();
667
TRIGGER_J9HOOK_MM_INTERRUPT_COMPILATION(_extensions->hookInterface, (J9VMThread *)env->getLanguageVMThread());
668
#if defined(J9VM_JIT_CLASS_UNLOAD_RWMONITOR)
669
omrthread_rwmutex_enter_write(_javaVM->classUnloadMutex);
670
#else
671
omrthread_monitor_enter(_javaVM->classUnloadMutex);
672
#endif /* J9VM_JIT_CLASS_UNLOAD_RWMONITOR */
673
U_64 endTime = j9time_hires_clock();
674
quiesceTime = j9time_hires_delta(startTime, endTime, J9PORT_TIME_DELTA_IN_MICROSECONDS);
675
}
676
return quiesceTime;
677
}
678
679
void
680
MM_ClassLoaderManager::exitClassUnloadMutex(MM_EnvironmentBase *env)
681
{
682
/* If we allowed class unloading during this gc, we must release the classUnloadMutex */
683
#if defined(J9VM_JIT_CLASS_UNLOAD_RWMONITOR)
684
omrthread_rwmutex_exit_write(_javaVM->classUnloadMutex);
685
#else
686
omrthread_monitor_exit(_javaVM->classUnloadMutex);
687
#endif /* J9VM_JIT_CLASS_UNLOAD_RWMONITOR */
688
}
689
690
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
691
692
693
#if defined(J9VM_GC_REALTIME)
694
/* TODO CRGTMP Remove #if defined once non-realtime collectors use classLoaderManager during
695
* unloadDeadClassLoaders. This was added to fix CMVC 127599 until stability week is over
696
*/
697
extern "C" {
698
699
void classLoaderLoadHook(J9HookInterface** hook, UDATA eventNum, void* eventData, void* userData)
700
{
701
J9VMClassLoaderInitializedEvent* event = (J9VMClassLoaderInitializedEvent*)eventData;
702
MM_ClassLoaderManager *manager = (MM_ClassLoaderManager *)userData;
703
/* TODO CRGTMP should we be setting the SCANNED bit on the classloader if we are in trace phase? */
704
manager->linkClassLoader(event->classLoader);
705
}
706
707
}
708
#endif /* J9VM_GC_REALTIME */
709
710