-
Notifications
You must be signed in to change notification settings - Fork 748
/
Copy pathObjectModel.hpp
696 lines (629 loc) · 22.5 KB
/
ObjectModel.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
/*******************************************************************************
* Copyright IBM Corp. and others 1991
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] https://openjdk.org/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
*******************************************************************************/
/**
* @file
* @ingroup GC_Base
*/
#if !defined(OBJECTMODEL_HPP_)
#define OBJECTMODEL_HPP_
/* @ddr_namespace: default */
#include <assert.h>
#include "j9.h"
#include "j9cfg.h"
#include "j9consts.h"
#include "j9nonbuilder.h"
#include "modron.h"
#include "j9modron.h"
#include "objectdescription.h"
#include "util_api.h"
#include "ArrayObjectModel.hpp"
#include "ArrayletObjectModel.hpp"
#include "AtomicOperations.hpp"
#include "ForwardedHeader.hpp"
#include "HeapLinkedFreeHeader.hpp"
#include "MixedObjectModel.hpp"
#include "ObjectModelBase.hpp"
#include "ObjectModelDelegate.hpp"
#if defined(OMR_GC_REALTIME)
/* this bit is set in the object header slot if an overflow condition is raised */
#define GC_OVERFLOW 0x4
#endif /* defined(OMR_GC_REALTIME) */
/*
* #defines representing the scope depth stored in each object header
* use two low bits of Collector Bits for Depth
*/
#define OBJECT_HEADER_DEPTH_ZERO 0
#define OBJECT_HEADER_DEPTH_MAX 3
#define OBJECT_HEADER_DEPTH_SHIFT OMR_OBJECT_METADATA_AGE_SHIFT
#define OBJECT_HEADER_DEPTH_MASK (OBJECT_HEADER_DEPTH_MAX << OBJECT_HEADER_DEPTH_SHIFT)
/* check that we have enough collector bits to be used for Depth */
#if (0 != (OBJECT_HEADER_DEPTH_MASK & ~(OMR_OBJECT_METADATA_AGE_MASK)))
#error "Some OBJECT_HEADER_DEPTH_MASK bits are out of range of OMR_OBJECT_METADATA_AGE_MASK."
#endif /* (0 != (OBJECT_HEADER_DEPTH_MASK & ~(OMR_OBJECT_METADATA_AGE_MASK))) */
/*
* #defines representing the 2 bits stored in immortal object header used as mark and overflow bits by ReferenceChainWalker.
* Both bits occupy the arraylet layout bits which have been deprecated
*/
#define OBJECT_HEADER_REFERENCE_CHAIN_WALKER_IMMORTAL_MARKED 0x40
#define OBJECT_HEADER_REFERENCE_CHAIN_WALKER_IMMORTAL_OVERFLOW 0xC0
/* Object header flag bits used for lazy hashcode insertion on copy/move */
#define OMR_GC_DEFERRED_HASHCODE_INSERTION
class MM_AllocateInitialization;
class MM_EnvironmentBase;
class MM_GCExtensionsBase;
/**
* Provides information for a given object.
* @ingroup GC_Base
*/
class GC_ObjectModel : public GC_ObjectModelBase
{
/*
* Member data and types
*/
private:
J9JavaVM* _javaVM; /***< pointer to the Java VM */
GC_MixedObjectModel *_mixedObjectModel; /**< pointer to the mixed object model in extensions (so that we can delegate to it) */
GC_ArrayObjectModel *_indexableObjectModel; /**< pointer to the indexable object model in extensions (so that we can delegate to it) */
J9Class *_classClass; /**< java.lang.Class class pointer for detecting special objects */
J9Class *_classLoaderClass; /**< java.lang.ClassLoader class pointer for detecting special objects */
J9Class *_continuationClass; /**< jdk/internal/vm/Continuation class pointer for detecting subclass of Continuation */
J9Class *_atomicMarkableReferenceClass; /**< java.util.concurrent.atomic.AtomicMarkableReference class pointer for detecting special objects */
protected:
public:
/**
* Return values for getScanType().
*/
enum ScanType {
SCAN_INVALID_OBJECT = 0,
SCAN_MIXED_OBJECT = 1,
SCAN_POINTER_ARRAY_OBJECT = 2,
SCAN_PRIMITIVE_ARRAY_OBJECT = 3,
SCAN_REFERENCE_MIXED_OBJECT = 4,
SCAN_CLASS_OBJECT = 5,
SCAN_CLASSLOADER_OBJECT = 6,
SCAN_ATOMIC_MARKABLE_REFERENCE_OBJECT = 7,
SCAN_OWNABLESYNCHRONIZER_OBJECT = 8,
SCAN_MIXED_OBJECT_LINKED = 9,
SCAN_FLATTENED_ARRAY_OBJECT = 10,
SCAN_CONTINUATION_OBJECT = 11
};
/**
* Values for the 'state' field in java.lang.ref.Reference.
* Note that these values are mirrored in the Java code. Do not change them.
*/
enum ReferenceState {
REF_STATE_INITIAL = 0, /**< indicates the initial (normal) state for a Reference object. Referent is weak. */
REF_STATE_CLEARED = 1, /**< indicates that the Reference object has been cleared, either by the GC or by the Java clear() API. Referent is null or strong. */
REF_STATE_ENQUEUED = 2, /**< indicates that the Reference object has been cleared and enqueued on its ReferenceQueue. Referent is null or strong. */
REF_STATE_REMEMBERED = 3, /**< indicates that the Reference object was discovered by a global cycle and that the current local GC cycle must return it to that list and restore the state to INITIAL. */
};
/*
* Member functions
*/
private:
/**
* Determine the scan type for an instant of the specified class.
* The class has the J9AccClassGCSpecial bit set.
* @param[in] objectClazz the class of the object to identify
* @return one of the ScanType constants
*/
ScanType getSpecialClassScanType(J9Class *objectClazz);
/**
* Examine all classes as they are loaded to determine if they require the J9AccClassGCSpecial bit.
* These classes are handled specially by GC_ObjectModel::getScanType()
*/
static void internalClassLoadHook(J9HookInterface** hook, uintptr_t eventNum, void* eventData, void* userData);
/**
* Update all of the GC special class pointers to their most current version after a class
* redefinition has occurred.
*/
static void classesRedefinedHook(J9HookInterface** hook, uintptr_t eventNum, void* eventData, void* userData);
/**
* Returns the shape of an class.
* @param objectPtr Pointer to object whose shape is required.
* @return The shape of the object
*/
MMINLINE uintptr_t
getClassShape(J9Object *objectPtr)
{
J9Class* clazz = J9GC_J9OBJECT_CLAZZ(objectPtr, this);
return J9GC_CLASS_SHAPE(clazz);
}
public:
/**
* Determine the ScanType code for objects of the specified class. This code determines how instances should be scanned.
* @param clazz[in] the class of the object to be scanned
* @return a ScanType code, SCAN_INVALID_OBJECT if the code cannot be determined due to an error
*/
MMINLINE ScanType
getScanType(J9Class *clazz)
{
ScanType result = SCAN_INVALID_OBJECT;
switch(J9GC_CLASS_SHAPE(clazz)) {
case OBJECT_HEADER_SHAPE_MIXED:
{
uintptr_t classFlags = J9CLASS_FLAGS(clazz) & (J9AccClassReferenceMask | J9AccClassGCSpecial | J9AccClassOwnableSynchronizer | J9AccClassContinuation);
if (0 == classFlags) {
if (0 != clazz->selfReferencingField1) {
result = SCAN_MIXED_OBJECT_LINKED;
} else {
result = SCAN_MIXED_OBJECT;
}
} else {
if (0 != (classFlags & J9AccClassReferenceMask)) {
result = SCAN_REFERENCE_MIXED_OBJECT;
} else if (0 != (classFlags & J9AccClassGCSpecial)) {
result = getSpecialClassScanType(clazz);
} else if (0 != (classFlags & J9AccClassOwnableSynchronizer)) {
result = SCAN_OWNABLESYNCHRONIZER_OBJECT;
} else if (0 != (classFlags & J9AccClassContinuation)) {
result = SCAN_CONTINUATION_OBJECT;
} else {
/* Assert_MM_unreachable(); */
assert(false);
}
}
break;
}
case OBJECT_HEADER_SHAPE_POINTERS:
if (J9_IS_J9CLASS_FLATTENED(clazz)) {
if (J9CLASS_HAS_REFERENCES(((J9ArrayClass *)clazz)->leafComponentType)) {
result = SCAN_FLATTENED_ARRAY_OBJECT;
} else {
result = SCAN_PRIMITIVE_ARRAY_OBJECT;
}
} else {
result = SCAN_POINTER_ARRAY_OBJECT;
}
break;
case OBJECT_HEADER_SHAPE_DOUBLES:
case OBJECT_HEADER_SHAPE_BYTES:
case OBJECT_HEADER_SHAPE_WORDS:
case OBJECT_HEADER_SHAPE_LONGS:
/* Must be a primitive array*/
result = SCAN_PRIMITIVE_ARRAY_OBJECT;
break;
default:
result = SCAN_INVALID_OBJECT;
}
return result;
}
MMINLINE ScanType
getScanType(J9Object *objectPtr)
{
J9Class *clazz = J9GC_J9OBJECT_CLAZZ(objectPtr, this);
return getScanType(clazz);
}
/**
* Returns the depth of an object.
* @param objectPtr Pointer to object whose depth is required.
* @return The depth of the object
*/
MMINLINE uintptr_t
getObjectDepth(J9Object *objectPtr)
{
return (getRememberedBits(objectPtr) & OBJECT_HEADER_DEPTH_MASK);
}
/**
* Returns TRUE if a class is indexable, FALSE otherwise.
* @param clazz Pointer to the class
* @return TRUE if a class is indexable, FALSE otherwise
*/
MMINLINE bool
isIndexable(J9Class* clazz)
{
return J9GC_CLASS_IS_ARRAY(clazz);
}
using GC_ObjectModelBase::isIndexable;
/**
* Returns TRUE if an object has a OBJECT_HEADER_SHAPE_POINTERS shape, FALSE otherwise.
* @param objectPtr Pointer to an object
* @return TRUE if an object has a OBJECT_HEADER_SHAPE_POINTERS shape, FALSE otherwise
*/
MMINLINE bool
isObjectArray(J9Object *objectPtr)
{
J9Class* clazz = J9GC_J9OBJECT_CLAZZ(objectPtr, this);
return (OBJECT_HEADER_SHAPE_POINTERS == J9GC_CLASS_SHAPE(clazz));
}
/**
* @see isObjectArray(J9Object *objectPtr)
*/
MMINLINE bool
isObjectArray(J9IndexableObject *objectPtr)
{
return isObjectArray((J9Object*)objectPtr);
}
/**
* Returns TRUE if an object is primitive array, FALSE otherwise.
* @param objectPtr Pointer to an object
* @return TRUE if an object is primitive array, FALSE otherwise
*/
MMINLINE bool
isPrimitiveArray(J9Object *objectPtr)
{
bool isPrimitiveArray = false;
switch(getClassShape(objectPtr)) {
case OBJECT_HEADER_SHAPE_BYTES:
case OBJECT_HEADER_SHAPE_WORDS:
case OBJECT_HEADER_SHAPE_LONGS:
case OBJECT_HEADER_SHAPE_DOUBLES:
isPrimitiveArray = true;
break;
default:
isPrimitiveArray = false;
break;
}
return isPrimitiveArray;
}
/**
* @see isPrimitiveArray(J9Object *objectPtr)
*/
MMINLINE bool
isPrimitiveArray(J9IndexableObject *objectPtr)
{
return isPrimitiveArray((J9Object*)objectPtr);
}
/**
* Determine whether or not the given object is a double array
*
* @return true if objectPtr is a double array
* @return false otherwise
*/
MMINLINE bool
isDoubleArray(J9Object* objectPtr)
{
return (OBJECT_HEADER_SHAPE_DOUBLES == getClassShape(objectPtr));
}
/**
* @see isDoubleArray(J9Object* objectPtr)
*/
MMINLINE bool
isDoubleArray(J9IndexableObject *objectPtr)
{
return isDoubleArray((J9Object*)objectPtr);
}
/**
* Check is indexable bit set properly:
* must be set for arrays and primitive arrays
* must not be set for all others
* @param objectPtr Pointer to an object
* @return TRUE if indexable bit is set properly
*/
MMINLINE bool
checkIndexableFlag(J9Object *objectPtr)
{
bool result = false;
if (isObjectArray(objectPtr) || isPrimitiveArray(objectPtr)) {
if (isIndexable(objectPtr)) {
result = true;
}
} else {
if (!isIndexable(objectPtr)) {
result = true;
}
}
return result;
}
/**
* Determine the basic hash code for the specified object. This may modify the object. For example, it may
* set the HAS_BEEN_HASHED bit in the object's header. Object must not be NULL.
*
* @param object[in] the object to be hashed
* @return the persistent, basic hash code for the object
*/
MMINLINE int32_t
getObjectHashCode(J9JavaVM *vm, J9Object *object)
{
int32_t result = 0;
#if defined (OMR_GC_MODRON_COMPACTION) || defined (J9VM_GC_GENERATIONAL)
if (hasBeenMoved(object)) {
uintptr_t hashOffset = getHashcodeOffset(object);
result = *(int32_t*)((uint8_t*)object + hashOffset);
} else {
atomicSetObjectFlags(object, 0, OBJECT_HEADER_HAS_BEEN_HASHED_IN_CLASS);
result = convertValueToHash(vm, (uintptr_t)object);
}
#else /* defined (OMR_GC_MODRON_COMPACTION) || defined (J9VM_GC_GENERATIONAL) */
result = computeObjectAddressToHash(vm, object);
#endif /* defined (OMR_GC_MODRON_COMPACTION) || defined (J9VM_GC_GENERATIONAL) */
return result;
}
/**
* Initialize the basic hash code for the specified object.
* Space for the hash slot must already exist.
*
* @note Sets OBJECT_HEADER_HAS_BEEN_MOVED_IN_CLASS | OBJECT_HEADER_HAS_BEEN_HASHED_IN_CLASS flags
* @param object[in] the object to be initialized.
*/
MMINLINE void
initializeHashSlot(J9JavaVM* vm, J9Object *objectPtr)
{
#if defined (OMR_GC_MODRON_COMPACTION) || defined (J9VM_GC_GENERATIONAL)
uintptr_t hashOffset = getHashcodeOffset(objectPtr);
uint32_t *hashCodePointer = (uint32_t*)((uint8_t*)objectPtr + hashOffset);
*hashCodePointer = convertValueToHash(vm, (uintptr_t)objectPtr);
setObjectHasBeenMoved(objectPtr);
#endif /* defined (OMR_GC_MODRON_COMPACTION) || defined (J9VM_GC_GENERATIONAL) */
}
/**
* Returns TRUE if an object has been hashed or moved, FALSE otherwise.
* @param objectPtr Object to test
* @return TRUE if an object has been hashed or moved, FALSE otherwise
*/
MMINLINE bool
hasBeenHashed(J9Object *objectPtr)
{
return hasBeenHashed(getObjectFlags(objectPtr));
}
MMINLINE bool
hasBeenHashed(uintptr_t objectFlags)
{
return 0 != (objectFlags & (OBJECT_HEADER_HAS_BEEN_HASHED_IN_CLASS | OBJECT_HEADER_HAS_BEEN_MOVED_IN_CLASS));
}
/**
* Returns TRUE if an object has been hashed but not moved, FALSE otherwise.
* @param objectPtr Object to test
* @return TRUE if an object has been hashed but not moved, FALSE otherwise
*/
MMINLINE bool
hasJustBeenHashed(J9Object *objectPtr)
{
return hasJustBeenHashed(getObjectFlags(objectPtr));
}
MMINLINE bool
hasJustBeenHashed(uintptr_t objectFlags)
{
return OBJECT_HEADER_HAS_BEEN_HASHED_IN_CLASS == (objectFlags & OBJECT_HEADER_HAS_BEEN_HASHED_IN_CLASS);
}
/**
* Returns TRUE if an object has been moved, regardless of state of hashed bit, FALSE otherwise.
* @param objectPtr Object to test
* @return TRUE if an object has been moved, regardless of state of hashed bit, FALSE otherwise
*/
MMINLINE bool
hasBeenMoved(J9Object *objectPtr)
{
return hasBeenMoved(getObjectFlags(objectPtr));
}
MMINLINE bool
hasBeenMoved(uintptr_t objectFlags)
{
return OBJECT_HEADER_HAS_BEEN_MOVED_IN_CLASS == (objectFlags & OBJECT_HEADER_HAS_BEEN_MOVED_IN_CLASS);
}
/**
* Returns TRUE if an object has been moved and hashed bit cleared, FALSE otherwise.
* @param objectPtr Object to test
* @return TRUE if an object has been moved and hashed bit cleared, FALSE otherwise
*/
MMINLINE bool
hasRecentlyBeenMoved(J9Object *objectPtr)
{
return hasRecentlyBeenMoved(getObjectFlags(objectPtr));
}
MMINLINE bool
hasRecentlyBeenMoved(uintptr_t objectFlags)
{
return OBJECT_HEADER_HAS_BEEN_MOVED_IN_CLASS == (objectFlags & (OBJECT_HEADER_HAS_BEEN_HASHED_IN_CLASS | OBJECT_HEADER_HAS_BEEN_MOVED_IN_CLASS));
}
/**
* Set OBJECT_HEADER_HAS_BEEN_MOVED and OBJECT_HEADER_HAS_BEEN_HASHED_IN_CLASS flags
* @param objectPtr Pointer to an object
*/
MMINLINE void
setObjectHasBeenMoved(omrobjectptr_t objectPtr)
{
setObjectFlags(objectPtr, 0, OBJECT_HEADER_HAS_BEEN_MOVED_IN_CLASS | OBJECT_HEADER_HAS_BEEN_HASHED_IN_CLASS);
}
/**
* Set OBJECT_HEADER_HAS_BEEN_MOVED flag / clear OBJECT_HEADER_HAS_BEEN_HASHED bit
* @param objectPtr Pointer to an object
*/
MMINLINE void
setObjectJustHasBeenMoved(omrobjectptr_t objectPtr)
{
setObjectFlags(objectPtr, OBJECT_HEADER_HAS_BEEN_HASHED_IN_CLASS, OBJECT_HEADER_HAS_BEEN_MOVED_IN_CLASS);
}
MMINLINE int32_t
computeObjectHash(MM_ForwardedHeader *forwardedHeader)
{
return convertValueToHash(_javaVM, (uintptr_t)forwardedHeader->getObject());
}
MMINLINE uintptr_t
getHashcodeOffset(omrobjectptr_t objectPtr) {
return getObjectModelDelegate()->getHashcodeOffset(objectPtr);
}
/**
* Same as getConsumedSizeInBytesWithHeader, except that it returns the size
* the object will consume if it is moved. i.e. it includes space for the
* hash code slot.
* @param objectPtr Pointer to an object
* @return The consumed heap size of an object, in bytes, including the header
*/
MMINLINE uintptr_t
getConsumedSizeInBytesWithHeaderForMove(J9Object *objectPtr)
{
return adjustSizeInBytes(getObjectModelDelegate()->getObjectSizeInBytesWithHeader(objectPtr, hasBeenHashed(objectPtr)));
}
/**
* Same as getConsumedSizeInBytesWithHeader, except that it returns the size
* the object will consume if it is moved. i.e. it includes space for the
* hash code slot.
* @param objectPtr Pointer to an object
* @return The consumed heap size of an object, in bytes, including the header
*/
MMINLINE uintptr_t
getConsumedSizeInBytesWithHeaderBeforeMove(J9Object *objectPtr)
{
return adjustSizeInBytes(getObjectModelDelegate()->getObjectSizeInBytesWithHeader(objectPtr, hasBeenMoved(objectPtr) && !hasRecentlyBeenMoved(objectPtr)));
}
#if defined(J9VM_GC_MODRON_SCAVENGER)
/**
* Extract the class pointer from an unforwarded object.
*
* This method will assert if the object has been marked as forwarded.
*
* @param[in] pointer to forwardedHeader the MM_ForwardedHeader instance encapsulating the object
* @return pointer to the J9Class from the object encapsulated by forwardedHeader
* @see MM_ForwardingHeader::isForwardedObject()
*/
MMINLINE J9Class *
getPreservedClass(MM_ForwardedHeader *forwardedHeader)
{
return (J9Class *)((uintptr_t)(forwardedHeader->getPreservedSlot()) & J9GC_J9OBJECT_CLAZZ_ADDRESS_MASK);
}
/**
* Update the new version of this object after it has been copied. This undoes any damaged
* caused by installing the forwarding pointer into the original prior to the copy, and sets
* the object age.
*
* This will install the correct (i.e. unforwarded) class pointer, update the hashed/moved
* flags and install the hash code if the object has been hashed but not previously moved.
*
* @param[in] forwardedHeader pointer to the MM_ForwardedHeader instance encapsulating the object
* @param[in] destinationObjectPtr pointer to the copied object to be fixed up
* @param[in] objectAge the age to set in the copied object
*/
MMINLINE void
fixupForwardedObject(MM_ForwardedHeader *forwardedHeader, omrobjectptr_t destinationObjectPtr, uintptr_t objectAge)
{
GC_ObjectModelBase::fixupForwardedObject(forwardedHeader, destinationObjectPtr, objectAge);
fixupHashFlagsAndSlot(forwardedHeader, destinationObjectPtr);
}
/**
* This will install the correct (i.e. unforwarded) class pointer, update the hashed/moved
* flags and install the hash code if the object has been hashed but not previously moved.
*
* @param[in] forwardedHeader pointer to the MM_ForwardedHeader instance encapsulating the object
* @param[in] destinationObjectPtr pointer to the copied object to be fixed up
*/
MMINLINE void
fixupHashFlagsAndSlot(MM_ForwardedHeader *forwardedHeader, omrobjectptr_t destinationObjectPtr)
{
/* To have ability to backout last scavenge we need to recognize objects just moved (moved first time) in current scavenge
*
* Bits State
* --------------------------------
* m h moved / hashed bits
* 0 0 not moved / not hashed
* 0 1 not moved / hashed
* 1 0 just moved / hashed
* 1 1 moved / hashed
* --------------------------------
*/
if (hasBeenMoved(getPreservedFlags(forwardedHeader))) {
if (hasRecentlyBeenMoved(getPreservedFlags(forwardedHeader))) {
/* Moved bit set / hashed bit not set means "moved previous scavenge" so set moved/hashed */
setObjectHasBeenMoved(destinationObjectPtr);
}
} else if (hasBeenHashed(getPreservedFlags(forwardedHeader))) {
/* The object has been hashed and has not been moved so we must store the previous address into the hashcode slot at hashcode offset. */
uintptr_t hashOffset;
J9Class *clazz = getPreservedClass(forwardedHeader);
if (isIndexable(clazz)) {
hashOffset = _indexableObjectModel->getPreservedHashcodeOffset(forwardedHeader);
} else {
hashOffset = _mixedObjectModel->getHashcodeOffset(clazz);
}
uint32_t *hashCodePointer = (uint32_t*)((uint8_t*) destinationObjectPtr + hashOffset);
*hashCodePointer = convertValueToHash(_javaVM, (uintptr_t)forwardedHeader->getObject());
setObjectJustHasBeenMoved(destinationObjectPtr);
}
}
#endif /* defined(J9VM_GC_MODRON_SCAVENGER) */
#if defined(OMR_GC_REALTIME)
/**
* Set GC_OVERFLOW bit atomically
* @param objectPtr Pointer to an object
* @return true, if GC_OVERFLOW bit has been set this call
*/
MMINLINE bool
atomicSetOverflowBit(J9Object *objectPtr)
{
return atomicSetObjectFlags(objectPtr, 0, GC_OVERFLOW);
}
/**
* Clear GC_OVERFLOW bit atomically
* @param objectPtr Pointer to an object
* @return true, if GC_OVERFLOW bit has been cleared this call
*/
MMINLINE bool
atomicClearOverflowBit(J9Object *objectPtr)
{
return atomicSetObjectFlags(objectPtr, GC_OVERFLOW, 0);
}
/**
* Return back true if GC_OVERFLOW bit is set
* @param objectPtr Pointer to an object
* @return true, if GC_OVERFLOW bit is set
*/
MMINLINE bool
isOverflowBitSet(J9Object *objectPtr)
{
return (GC_OVERFLOW == (J9GC_J9OBJECT_FLAGS_FROM_CLAZZ(objectPtr, this) & GC_OVERFLOW));
}
#endif /* defined(OMR_GC_REALTIME) */
/**
* Set class in clazz slot in object header, with header flags.
* @param objectPtr Pointer to an object
* @param clazz class pointer to set
* @param flags flag bits to set
*/
MMINLINE void
setObjectClassAndFlags(J9Object *objectPtr, J9Class* clazz, uintptr_t flags)
{
uintptr_t classBits = (uintptr_t)clazz;
uintptr_t flagsBits = flags & (uintptr_t)OMR_OBJECT_METADATA_FLAGS_MASK;
if (compressObjectReferences()) {
*((uint32_t*)getObjectHeaderSlotAddress(objectPtr)) = (uint32_t)(classBits | flagsBits);
} else {
*((uintptr_t*)getObjectHeaderSlotAddress(objectPtr)) = (classBits | flagsBits);
}
}
/**
* Set class in clazz slot in object header, preserving header flags
* @param objectPtr Pointer to an object
* @param clazz class pointer to set
*/
MMINLINE void
setObjectClass(J9Object *objectPtr, J9Class* clazz)
{
setObjectClassAndFlags(objectPtr, clazz, getObjectFlags(objectPtr));
}
/**
* Initialize the receiver, a new instance of GC_ObjectModel
*
* @return true on success, false on failure
*/
virtual bool initialize(MM_GCExtensionsBase *extensions);
/**
* Tear down the receiver
*/
virtual void tearDown(MM_GCExtensionsBase *extensions);
/**
* Constructor.
*/
GC_ObjectModel()
: GC_ObjectModelBase()
{}
};
#endif /* OBJECTMODEL_HPP_ */