Path: blob/master/runtime/gc_base/ObjectAccessBarrier.cpp
5986 views
/*******************************************************************************1* Copyright (c) 1991, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/212223/**24* @file25* @ingroup GC_Base26*/2728#include "ObjectAccessBarrier.hpp"2930#include "j9protos.h"31#include "ModronAssertions.h"32#include "rommeth.h"3334#include "ArrayletObjectModel.hpp"35#include "AtomicOperations.hpp"36#include "EnvironmentBase.hpp"37#include "HeapRegionManager.hpp"38#include "MemorySpace.hpp"39#include "ObjectAccessBarrierAPI.hpp"40#include "ObjectMonitor.hpp"41#include "VMHelpers.hpp"42#include "VMThreadListIterator.hpp"4344bool45MM_ObjectAccessBarrier::initialize(MM_EnvironmentBase *env)46{47_extensions = MM_GCExtensions::getExtensions(env);48_heap = _extensions->heap;49J9JavaVM *vm = (J9JavaVM*)env->getOmrVM()->_language_vm;50OMR_VM *omrVM = env->getOmrVM();51char *refSignature = (char*) "I";5253if (sizeof(U_64) == J9JAVAVM_REFERENCE_SIZE(vm)) {54refSignature = (char *) "J";55}5657#if defined(OMR_GC_COMPRESSED_POINTERS)58if (env->compressObjectReferences()) {5960#if defined(J9VM_GC_REALTIME)61/*62* Do not allow 4-bit shift for Metronome63* Cell Sizes Table for Segregated heap should be modified to have aligned to 16 values64*/65if (_extensions->isMetronomeGC()) {66if (DEFAULT_LOW_MEMORY_HEAP_CEILING_SHIFT < omrVM->_compressedPointersShift) {67/* Non-standard NLS message required */68_extensions->heapInitializationFailureReason = MM_GCExtensionsBase::HEAP_INITIALIZATION_FAILURE_REASON_METRONOME_DOES_NOT_SUPPORT_4BIT_SHIFT;69return false;70}71}72#endif /* J9VM_GC_REALTIME */7374#if defined(OMR_GC_FULL_POINTERS)75_compressObjectReferences = true;76#endif /* defined(OMR_GC_FULL_POINTERS) */77_compressedPointersShift = omrVM->_compressedPointersShift;78vm->compressedPointersShift = omrVM->_compressedPointersShift;79Trc_MM_CompressedAccessBarrierInitialized(env->getLanguageVMThread(), 0, _compressedPointersShift);80}81#endif /* defined(OMR_GC_COMPRESSED_POINTERS) */8283vm->objectAlignmentInBytes = omrVM->_objectAlignmentInBytes;84vm->objectAlignmentShift = omrVM->_objectAlignmentShift;8586/* request an extra slot in java/lang/ref/Reference which we will use to maintain linked lists of reference objects */87if (0 != vm->internalVMFunctions->addHiddenInstanceField(vm, "java/lang/ref/Reference", "gcLink", refSignature, &_referenceLinkOffset)) {88return false;89}90/* request an extra slot in java/util/concurrent/locks/AbstractOwnableSynchronizer which we will use to maintain linked lists of ownable synchronizer objects */91if (0 != vm->internalVMFunctions->addHiddenInstanceField(vm, "java/util/concurrent/locks/AbstractOwnableSynchronizer", "ownableSynchronizerLink", refSignature, &_ownableSynchronizerLinkOffset)) {92return false;93}9495return true;96}9798void99MM_ObjectAccessBarrier::kill(MM_EnvironmentBase *env)100{101tearDown(env);102env->getForge()->free(this);103}104105void106MM_ObjectAccessBarrier::tearDown(MM_EnvironmentBase *env)107{108}109110/**111* Read an object pointer from an object.112* This function is only concerned with moving the actual data. Do not re-implement113* unless the value is stored in a non-native format (e.g. compressed object pointers).114* See readObject() for higher-level actions.115* By default, forwards to readU32Impl() on 32-bit platforms, and readU64Impl() on 64-bit.116* @param srcObject the object being read from117* @param srcAddress the address of the field to be read118* @param isVolatile non-zero if the field is volatile, zero otherwise119*/120mm_j9object_t121MM_ObjectAccessBarrier::readObjectImpl(J9VMThread *vmThread, mm_j9object_t srcObject, fj9object_t *srcAddress, bool isVolatile)122{123mm_j9object_t result = NULL;124if (compressObjectReferences()) {125result = convertPointerFromToken(*(uint32_t*)srcAddress);126} else {127result = (mm_j9object_t)*(uintptr_t*)srcAddress;128}129return result;130}131132/**133* Read a static object field.134* This function is only concerned with moving the actual data. Do not re-implement135* unless the value is stored in a non-native format (e.g. compressed object pointers).136* See staticReadObject() for higher-level actions.137* By default, forwards to readU32Impl() on 32-bit platforms, and readU64Impl() on 64-bit.138* @param clazz the class which contains the static field139* @param srcAddress the address of the field to be read140* @param isVolatile non-zero if the field is volatile, zero otherwise141*/142mm_j9object_t143MM_ObjectAccessBarrier::staticReadObjectImpl(J9VMThread *vmThread, J9Class *clazz, j9object_t *srcAddress, bool isVolatile)144{145return *srcAddress;146}147148/**149* Read an object from an internal VM slot (J9VMThread, J9JavaVM, named field of J9Class).150* This function is only concerned with moving the actual data. Do not re-implement151* unless the value is stored in a non-native format (e.g. compressed object pointers).152* See readObjectFromInternalVMSlot() for higher-level actions.153* By default, forwards to readU32Impl() on 32-bit platforms, and readU64Impl() on 64-bit.154* @param srcAddress the address of the field to be read155* @param isVolatile non-zero if the field is volatile, zero otherwise156*/157mm_j9object_t158MM_ObjectAccessBarrier::readObjectFromInternalVMSlotImpl(J9VMThread *vmThread, j9object_t *srcAddress, bool isVolatile)159{160return *srcAddress;161}162163/**164* Store an object pointer into an object.165* This function is only concerned with moving the actual data. Do not re-implement166* unless the value is stored in a non-native format (e.g. compressed object pointers).167* See storeObject() for higher-level actions.168* By default, forwards to storeU32Impl() on 32-bit platforms, and storeU64Impl() on 64-bit.169* @param destObject the object to read from170* @param destAddress the address of the field to be read171* @param value the value to be stored172* @param isVolatile non-zero if the field is volatile, zero otherwise173*/174void175MM_ObjectAccessBarrier::storeObjectImpl(J9VMThread *vmThread, mm_j9object_t destObject, fj9object_t *destAddress, mm_j9object_t value, bool isVolatile)176{177if (compressObjectReferences()) {178*(uint32_t*)destAddress = (uint32_t)convertTokenFromPointer(value);179} else {180*(uintptr_t*)destAddress = (uintptr_t)value;181}182}183184/**185* Store a static field.186* This function is only concerned with moving the actual data. Do not re-implement187* unless the value is stored in a non-native format (e.g. compressed object pointers).188* See storeObject() for higher-level actions.189* By default, forwards to storeU32Impl() on 32-bit platforms, and storeU64Impl() on 64-bit.190* @param clazz the class the field belongs to191* @param destAddress the address of the field to be read192* @param value the value to be stored193* @param isVolatile non-zero if the field is volatile, zero otherwise194*/195void196MM_ObjectAccessBarrier::staticStoreObjectImpl(J9VMThread *vmThread, J9Class* clazz, j9object_t *destAddress, mm_j9object_t value, bool isVolatile)197{198*destAddress = value;199}200201/**202* Write an object to an internal VM slot (J9VMThread, J9JavaVM, named field of J9Class).203* This function is only concerned with moving the actual data. Do not re-implement204* unless the value is stored in a non-native format (e.g. compressed object pointers).205* See storeObject() for higher-level actions.206* By default, forwards to storeU32Impl() on 32-bit platforms, and storeU64Impl() on 64-bit.207* @param destAddress the address of the field to be read208* @param value the value to be stored209* @param isVolatile non-zero if the field is volatile, zero otherwise210*/211void212MM_ObjectAccessBarrier::storeObjectToInternalVMSlotImpl(J9VMThread *vmThread, j9object_t *destAddress, mm_j9object_t value, bool isVolatile)213{214*destAddress = value;215}216217/**218* Read a U_8 from an object.219* This function is only concerned with moving the actual data. Do not re-implement220* unless the value is stored in a non-native format (e.g. compressed object pointers).221*222* @param srcObject the object being read from223* @param srcAddress the address of the field to be read224* @param isVolatile non-zero if the field is volatile, zero otherwise225*/226U_8227MM_ObjectAccessBarrier::readU8Impl(J9VMThread *vmThread, mm_j9object_t srcObject, U_8 *srcAddress, bool isVolatile)228{229return *srcAddress;230}231232/**233* Store a U_8 into an object.234* This function is only concerned with moving the actual data. Do not re-implement235* unless the value is stored in a non-native format (e.g. compressed object pointers).236*237* @param destObject the object to read from238* @param destAddress the address of the field to be read239* @param value the value to be stored240* @param isVolatile non-zero if the field is volatile, zero otherwise241*/242void243MM_ObjectAccessBarrier::storeU8Impl(J9VMThread *vmThread, mm_j9object_t destObject, U_8 *destAddress, U_8 value, bool isVolatile)244{245*destAddress = value;246}247248/**249* Read a I_8 from an object.250* This function is only concerned with moving the actual data. Do not re-implement251* unless the value is stored in a non-native format (e.g. compressed object pointers).252*253* @param srcObject the object being read from254* @param srcAddress the address of the field to be read255* @param isVolatile non-zero if the field is volatile, zero otherwise256*/257I_8258MM_ObjectAccessBarrier::readI8Impl(J9VMThread *vmThread, mm_j9object_t srcObject, I_8 *srcAddress, bool isVolatile)259{260return *srcAddress;261}262263/**264* Store a I_8 into an object.265* This function is only concerned with moving the actual data. Do not re-implement266* unless the value is stored in a non-native format (e.g. compressed object pointers).267*268* @param destObject the object to read from269* @param destAddress the address of the field to be read270* @param value the value to be stored271* @param isVolatile non-zero if the field is volatile, zero otherwise272*/273void274MM_ObjectAccessBarrier::storeI8Impl(J9VMThread *vmThread, mm_j9object_t destObject, I_8 *destAddress, I_8 value, bool isVolatile)275{276*destAddress = value;277}278279/**280* Read a U_16 from an object.281* This function is only concerned with moving the actual data. Do not re-implement282* unless the value is stored in a non-native format (e.g. compressed object pointers).283*284* @param srcObject the object being read from285* @param srcAddress the address of the field to be read286* @param isVolatile non-zero if the field is volatile, zero otherwise287*/288U_16289MM_ObjectAccessBarrier::readU16Impl(J9VMThread *vmThread, mm_j9object_t srcObject, U_16 *srcAddress, bool isVolatile)290{291return *srcAddress;292}293294/**295* Store a U_16 into an object.296* This function is only concerned with moving the actual data. Do not re-implement297* unless the value is stored in a non-native format (e.g. compressed object pointers).298*299* @param destObject the object to read from300* @param destAddress the address of the field to be read301* @param value the value to be stored302* @param isVolatile non-zero if the field is volatile, zero otherwise303*/304void305MM_ObjectAccessBarrier::storeU16Impl(J9VMThread *vmThread, mm_j9object_t destObject, U_16 *destAddress, U_16 value, bool isVolatile)306{307*destAddress = value;308}309310/**311* Read a I_16 from an object.312* This function is only concerned with moving the actual data. Do not re-implement313* unless the value is stored in a non-native format (e.g. compressed object pointers).314*315* @param srcObject the object being read from316* @param srcAddress the address of the field to be read317* @param isVolatile non-zero if the field is volatile, zero otherwise318*/319I_16320MM_ObjectAccessBarrier::readI16Impl(J9VMThread *vmThread, mm_j9object_t srcObject, I_16 *srcAddress, bool isVolatile)321{322return *srcAddress;323}324325/**326* Store a I_16 into an object.327* This function is only concerned with moving the actual data. Do not re-implement328* unless the value is stored in a non-native format (e.g. compressed object pointers).329*330* @param destObject the object to read from331* @param destAddress the address of the field to be read332* @param value the value to be stored333* @param isVolatile non-zero if the field is volatile, zero otherwise334*/335void336MM_ObjectAccessBarrier::storeI16Impl(J9VMThread *vmThread, mm_j9object_t destObject, I_16 *destAddress, I_16 value, bool isVolatile)337{338*destAddress = value;339}340341/**342* Read a U_32 from an object.343* This function is only concerned with moving the actual data. Do not re-implement344* unless the value is stored in a non-native format (e.g. compressed object pointers).345* See readU32() for higher-level actions.346* @param srcObject the object being read from347* @param srcAddress the address of the field to be read348* @param isVolatile non-zero if the field is volatile, zero otherwise349*/350U_32351MM_ObjectAccessBarrier::readU32Impl(J9VMThread *vmThread, mm_j9object_t srcObject, U_32 *srcAddress, bool isVolatile)352{353return *srcAddress;354}355356/**357* Store a U_32 into an object.358* This function is only concerned with moving the actual data. Do not re-implement359* unless the value is stored in a non-native format (e.g. compressed object pointers).360* See storeU32() for higher-level actions.361* @param destObject the object to read from362* @param destAddress the address of the field to be read363* @param value the value to be stored364* @param isVolatile non-zero if the field is volatile, zero otherwise365*/366void367MM_ObjectAccessBarrier::storeU32Impl(J9VMThread *vmThread, mm_j9object_t destObject, U_32 *destAddress, U_32 value, bool isVolatile)368{369*destAddress = value;370}371372/**373* Read a I_32 from an object.374* This function is only concerned with moving the actual data. Do not re-implement375* unless the value is stored in a non-native format (e.g. compressed object pointers).376* See readI32() for higher-level actions.377* By default, forwards to readU32Impl, and casts the return value.378* @param srcObject the object being read from379* @param srcAddress the address of the field to be read380* @param isVolatile non-zero if the field is volatile, zero otherwise381*/382I_32383MM_ObjectAccessBarrier::readI32Impl(J9VMThread *vmThread, mm_j9object_t srcObject, I_32 *srcAddress, bool isVolatile)384{385return *srcAddress;386}387388/**389* Store a U_32 into an object.390* This function is only concerned with moving the actual data. Do not re-implement391* unless the value is stored in a non-native format (e.g. compressed object pointers).392* See storeI32() for higher-level actions.393* By default, casts the value to unsigned and forwards to storeU32().394* @param destObject the object to read from395* @param destAddress the address of the field to be read396* @param value the value to be stored397* @param isVolatile non-zero if the field is volatile, zero otherwise398*/399void400MM_ObjectAccessBarrier::storeI32Impl(J9VMThread *vmThread, mm_j9object_t destObject, I_32 *destAddress, I_32 value, bool isVolatile)401{402*destAddress = value;403}404405/**406* Read a U_64 from an object.407* This function is only concerned with moving the actual data. Do not re-implement408* unless the value is stored in a non-native format (e.g. compressed object pointers).409* See readU64() for higher-level actions.410* @param srcObject the object being read from411* @param srcAddress the address of the field to be read412* @param isVolatile non-zero if the field is volatile, zero otherwise413*/414U_64415MM_ObjectAccessBarrier::readU64Impl(J9VMThread *vmThread, mm_j9object_t srcObject, U_64 *srcAddress, bool isVolatile)416{417#if !defined(J9VM_ENV_DATA64)418if (isVolatile) {419return longVolatileRead(vmThread, srcAddress);420}421#endif /* J9VM_ENV_DATA64 */422return *srcAddress;423}424425/**426* Store a U_64 into an object.427* This function is only concerned with moving the actual data. Do not re-implement428* unless the value is stored in a non-native format (e.g. compressed object pointers).429* See storeU64() for higher-level actions.430* @param destObject the object to read from431* @param destAddress the address of the field to be read432* @param value the value to be stored433* @param isVolatile non-zero if the field is volatile, zero otherwise434*/435void436MM_ObjectAccessBarrier::storeU64Impl(J9VMThread *vmThread, mm_j9object_t destObject, U_64 *destAddress, U_64 value, bool isVolatile)437{438#if !defined(J9VM_ENV_DATA64)439if (isVolatile) {440longVolatileWrite(vmThread, destAddress, &value);441return;442}443#endif /* J9VM_ENV_DATA64 */444*destAddress = value;445}446447/**448* Read a I_64 from an object.449* This function is only concerned with moving the actual data. Do not re-implement450* unless the value is stored in a non-native format (e.g. compressed object pointers).451* See readI64() for higher-level actions.452* By default, forwards to readU64Impl, and casts the return value.453* @param srcObject the object being read from454* @param srcAddress the address of the field to be read455* @param isVolatile non-zero if the field is volatile, zero otherwise456*/457I_64458MM_ObjectAccessBarrier::readI64Impl(J9VMThread *vmThread, mm_j9object_t srcObject, I_64 *srcAddress, bool isVolatile)459{460#if !defined(J9VM_ENV_DATA64)461if (isVolatile) {462return longVolatileRead(vmThread, (U_64 *)srcAddress);463}464#endif /* J9VM_ENV_DATA64 */465return *srcAddress;466}467468/**469* Store an I_64 into an object.470* This function is only concerned with moving the actual data. Do not re-implement471* unless the value is stored in a non-native format (e.g. compressed object pointers).472* See storeI64() for higher-level actions.473* By default, casts the value to unsigned and forwards to storeU64Impl().474* @param destObject the object to read from475* @param destAddress the address of the field to be read476* @param value the value to be stored477* @param isVolatile non-zero if the field is volatile, zero otherwise478*/479void480MM_ObjectAccessBarrier::storeI64Impl(J9VMThread *vmThread, mm_j9object_t destObject, I_64 *destAddress, I_64 value, bool isVolatile)481{482#if !defined(J9VM_ENV_DATA64)483if (isVolatile) {484longVolatileWrite(vmThread, (U_64 *)destAddress, (U_64 *)&value);485return;486}487#endif /* J9VM_ENV_DATA64 */488*destAddress = value;489}490491/**492* Read a non-object address (pointer to internal VM data) from an object.493* This function is only concerned with moving the actual data. Do not re-implement494* unless the value is stored in a non-native format (e.g. compressed object pointers).495* See readAddress() for higher-level actions.496* By default, forwards to readU32Impl() on 32-bit platforms, and readU64Impl() on 64-bit.497* @param srcObject the object being read from498* @param srcAddress the address of the field to be read499* @param isVolatile non-zero if the field is volatile, zero otherwise500*/501void *502MM_ObjectAccessBarrier::readAddressImpl(J9VMThread *vmThread, mm_j9object_t srcObject, void **srcAddress, bool isVolatile)503{504return *srcAddress;505}506507/**508* Store a non-object address into an object.509* This function is only concerned with moving the actual data. Do not re-implement510* unless the value is stored in a non-native format (e.g. compressed object pointers).511* See storeAddress() for higher-level actions.512* By default, forwards to storeU32Impl on 32-bit platforms and storeU64Impl on 64-bit.513* @param destObject the object to read from514* @param destAddress the address of the field to be read515* @param value the value to be stored516* @param isVolatile non-zero if the field is volatile, zero otherwise517*/518void519MM_ObjectAccessBarrier::storeAddressImpl(J9VMThread *vmThread, mm_j9object_t destObject, void **destAddress, void *value, bool isVolatile)520{521*destAddress = value;522}523524/**525* Call before a read or write of a possibly volatile field.526* @note This must be used in tandem with protectIfVolatileAfter()527* @param isVolatile true if the field is volatile, false otherwise528* @param isRead true if the field is being read, false if it is being written529* @param isWide true if the field is wide (64-bit), false otherwise530*/531void532MM_ObjectAccessBarrier::protectIfVolatileBefore(J9VMThread *vmThread, bool isVolatile, bool isRead, bool isWide)533{534if (isVolatile) {535/* need to insert a sync instruction536* As this is inline, compiler should optimize this away when not necessary.537*/538if (!isRead) {539/* atomic writeBarrier */540MM_AtomicOperations::storeSync();541}542}543}544545/**546* Call after a read or write of a possibly volatile field.547* @note This must be used in tandem with protectIfVolatileBefore()548* @param isVolatile true if the field is volatile, false otherwise549* @param isRead true if the field is being read, false if it is being written550* @param isWide true if the field is wide (64-bit), false otherwise551*/552void553MM_ObjectAccessBarrier::protectIfVolatileAfter(J9VMThread *vmThread, bool isVolatile, bool isRead, bool isWide)554{555if (isVolatile) {556/* need to insert a sync instruction557* As this is inline, compiler should optimize this away when not necessary.558*/559if (isRead) {560/* atomic readBarrier */561MM_AtomicOperations::loadSync();562} else {563/* atomic readWriteBarrier */564MM_AtomicOperations::sync();565}566}567}568569/**570* Read an object field: perform any pre-use barriers, calculate an effective address571* and perform the work.572* @param srcObject The object being used.573* @param srcOffset The offset of the field.574* @param isVolatile non-zero if the field is volatile.575*/576J9Object *577MM_ObjectAccessBarrier::mixedObjectReadObject(J9VMThread *vmThread, J9Object *srcObject, UDATA srcOffset, bool isVolatile)578{579fj9object_t *actualAddress = J9OAB_MIXEDOBJECT_EA(srcObject, srcOffset, fj9object_t);580J9Object *result = NULL;581582if (preObjectRead(vmThread, srcObject, actualAddress)) {583protectIfVolatileBefore(vmThread, isVolatile, true, false);584result = readObjectImpl(vmThread, srcObject, actualAddress, isVolatile);585protectIfVolatileAfter(vmThread, isVolatile, true, false);586587if (!postObjectRead(vmThread, srcObject, actualAddress)) {588result = NULL;589}590}591592/* This must always be called to massage the return value */593return result;594}595596/**597* Read an object field: perform any pre-use barriers, calculate an effective address598* and perform the work.599* @param srcObject The object being used.600* @param srcOffset The offset of the field.601* @param isVolatile non-zero if the field is volatile.602*/603void *604MM_ObjectAccessBarrier::mixedObjectReadAddress(J9VMThread *vmThread, J9Object *srcObject, UDATA srcOffset, bool isVolatile)605{606void **actualAddress = J9OAB_MIXEDOBJECT_EA(srcObject, srcOffset,void *);607protectIfVolatileBefore(vmThread, isVolatile, true, false);608void *result = readAddressImpl(vmThread, srcObject, actualAddress, isVolatile);609protectIfVolatileAfter(vmThread, isVolatile, true, false);610return result;611}612613/**614* Read an object field: perform any pre-use barriers, calculate an effective address615* and perform the work.616* @param srcObject The object being used.617* @param srcOffset The offset of the field.618* @param isVolatile non-zero if the field is volatile.619*/620U_32621MM_ObjectAccessBarrier::mixedObjectReadU32(J9VMThread *vmThread, J9Object *srcObject, UDATA srcOffset, bool isVolatile)622{623U_32 *actualAddress = J9OAB_MIXEDOBJECT_EA(srcObject, srcOffset, U_32);624protectIfVolatileBefore(vmThread, isVolatile, true, false);625U_32 result = readU32Impl(vmThread, srcObject, actualAddress, isVolatile);626protectIfVolatileAfter(vmThread, isVolatile, true, false);627return result;628}629630/**631* Read an object field: perform any pre-use barriers, calculate an effective address632* and perform the work.633* @param srcObject The object being used.634* @param srcOffset The offset of the field.635* @param isVolatile non-zero if the field is volatile.636*/637I_32638MM_ObjectAccessBarrier::mixedObjectReadI32(J9VMThread *vmThread, J9Object *srcObject, UDATA srcOffset, bool isVolatile)639{640I_32 *actualAddress = J9OAB_MIXEDOBJECT_EA(srcObject, srcOffset, I_32);641protectIfVolatileBefore(vmThread, isVolatile, true, false);642I_32 result = readI32Impl(vmThread, srcObject, actualAddress, isVolatile);643protectIfVolatileAfter(vmThread, isVolatile, true, false);644return result;645}646647/**648* Read an object field: perform any pre-use barriers, calculate an effective address649* and perform the work.650* @param srcObject The object being used.651* @param srcOffset The offset of the field.652* @param isVolatile non-zero if the field is volatile.653*/654U_64655MM_ObjectAccessBarrier::mixedObjectReadU64(J9VMThread *vmThread, J9Object *srcObject, UDATA srcOffset, bool isVolatile)656{657U_64 *actualAddress = J9OAB_MIXEDOBJECT_EA(srcObject, srcOffset, U_64);658protectIfVolatileBefore(vmThread, isVolatile, true, true);659U_64 result = readU64Impl(vmThread, srcObject, actualAddress, isVolatile);660protectIfVolatileAfter(vmThread, isVolatile, true, true);661return result;662}663664/**665* Read an object field: perform any pre-use barriers, calculate an effective address666* and perform the work.667* @param srcObject The object being used.668* @param srcOffset The offset of the field.669* @param isVolatile non-zero if the field is volatile.670*/671I_64672MM_ObjectAccessBarrier::mixedObjectReadI64(J9VMThread *vmThread, J9Object *srcObject, UDATA srcOffset, bool isVolatile)673{674I_64 *actualAddress = J9OAB_MIXEDOBJECT_EA(srcObject, srcOffset, I_64);675protectIfVolatileBefore(vmThread, isVolatile, true, true);676I_64 result = readI64Impl(vmThread, srcObject, actualAddress, isVolatile);677protectIfVolatileAfter(vmThread, isVolatile, true, true);678return result;679}680681/**682* Store an object field: perform any pre-use barriers, calculate an effective address683* and perform the work.684* @param destObject The object being used.685* @param destOffset The offset of the field.686* @param value The value to be stored687* @param isVolatile non-zero if the field is volatile.688*/689void690MM_ObjectAccessBarrier::mixedObjectStoreObject(J9VMThread *vmThread, J9Object *destObject, UDATA destOffset, J9Object *value, bool isVolatile)691{692fj9object_t *actualAddress = J9OAB_MIXEDOBJECT_EA(destObject, destOffset, fj9object_t);693694if (preObjectStore(vmThread, destObject, actualAddress, value, isVolatile)) {695protectIfVolatileBefore(vmThread, isVolatile, false, false);696storeObjectImpl(vmThread, destObject, actualAddress, value, isVolatile);697protectIfVolatileAfter(vmThread, isVolatile, false, false);698699postObjectStore(vmThread, destObject, actualAddress, value, isVolatile);700}701}702703/**704* Store an object field: perform any pre-use barriers, calculate an effective address705* and perform the work.706* @param destObject The object being used.707* @param destOffset The offset of the field.708* @param value The value to be stored709* @param isVolatile non-zero if the field is volatile.710*/711void712MM_ObjectAccessBarrier::mixedObjectStoreAddress(J9VMThread *vmThread, J9Object *destObject, UDATA destOffset,void *value, bool isVolatile)713{714void **actualAddress = J9OAB_MIXEDOBJECT_EA(destObject, destOffset,void *);715protectIfVolatileBefore(vmThread, isVolatile, false, false);716storeAddressImpl(vmThread, destObject, actualAddress, value, isVolatile);717protectIfVolatileAfter(vmThread, isVolatile, false, false);718}719720/**721* Store an object field: perform any pre-use barriers, calculate an effective address722* and perform the work.723* @param destObject The object being used.724* @param destOffset The offset of the field.725* @param value The value to be stored726* @param isVolatile non-zero if the field is volatile.727*/728void729MM_ObjectAccessBarrier::mixedObjectStoreU32(J9VMThread *vmThread, J9Object *destObject, UDATA destOffset, U_32 value, bool isVolatile)730{731U_32 *actualAddress = J9OAB_MIXEDOBJECT_EA(destObject, destOffset, U_32);732protectIfVolatileBefore(vmThread, isVolatile, false, false);733storeU32Impl(vmThread, destObject, actualAddress, value, isVolatile);734protectIfVolatileAfter(vmThread, isVolatile, false, false);735}736737/**738* Store an object field: perform any pre-use barriers, calculate an effective address739* and perform the work.740* @param destObject The object being used.741* @param destOffset The offset of the field.742* @param value The value to be stored743* @param isVolatile non-zero if the field is volatile.744*/745void746MM_ObjectAccessBarrier::mixedObjectStoreI32(J9VMThread *vmThread, J9Object *destObject, UDATA destOffset, I_32 value, bool isVolatile)747{748I_32 *actualAddress = J9OAB_MIXEDOBJECT_EA(destObject, destOffset, I_32);749protectIfVolatileBefore(vmThread, isVolatile, false, false);750storeI32Impl(vmThread, destObject, actualAddress, value, isVolatile);751protectIfVolatileAfter(vmThread, isVolatile, false, false);752}753754/**755* Store an object field: perform any pre-use barriers, calculate an effective address756* and perform the work.757* @param destObject The object being used.758* @param destOffset The offset of the field.759* @param value The value to be stored760* @param isVolatile non-zero if the field is volatile.761*/762void763MM_ObjectAccessBarrier::mixedObjectStoreU64(J9VMThread *vmThread, J9Object *destObject, UDATA destOffset, U_64 value, bool isVolatile)764{765U_64 *actualAddress = J9OAB_MIXEDOBJECT_EA(destObject, destOffset, U_64);766protectIfVolatileBefore(vmThread, isVolatile, false, true);767storeU64Impl(vmThread, destObject, actualAddress, value, isVolatile);768protectIfVolatileAfter(vmThread, isVolatile, false, true);769}770771/**772* Store an object field: perform any pre-use barriers, calculate an effective address773* and perform the work.774* @param destObject The object being used.775* @param destOffset The offset of the field.776* @param value The value to be stored777* @param isVolatile non-zero if the field is volatile.778*/779void780MM_ObjectAccessBarrier::mixedObjectStoreI64(J9VMThread *vmThread, J9Object *destObject, UDATA destOffset, I_64 value, bool isVolatile)781{782I_64 *actualAddress = J9OAB_MIXEDOBJECT_EA(destObject, destOffset, I_64);783protectIfVolatileBefore(vmThread, isVolatile, false, true);784storeI64Impl(vmThread, destObject, actualAddress, value, isVolatile);785protectIfVolatileAfter(vmThread, isVolatile, false, true);786}787788/**789* Read an array element: perform any pre-use barriers, calculate an effective address790* and perform the work.791* @param srcObject The array being used.792* @param srcIndex The element index793*/794J9Object *795MM_ObjectAccessBarrier::indexableReadObject(J9VMThread *vmThread, J9IndexableObject *srcObject, I_32 srcIndex, bool isVolatile)796{797UDATA const referenceSize = J9VMTHREAD_REFERENCE_SIZE(vmThread);798fj9object_t *actualAddress = (fj9object_t *)indexableEffectiveAddress(vmThread, srcObject, srcIndex, referenceSize);799J9Object *result = NULL;800801/* No preObjectRead yet because no barrier require it */802if (preObjectRead(vmThread, (J9Object *)srcObject, actualAddress)) {803protectIfVolatileBefore(vmThread, isVolatile, true, false);804result = readObjectImpl(vmThread, (J9Object*)srcObject, actualAddress);805protectIfVolatileAfter(vmThread, isVolatile, true, false);806807if (!postObjectRead(vmThread, (J9Object *)srcObject, actualAddress)) {808result = NULL;809}810}811812/* This must always be called to massage the return value */813return result;814}815816/**817* Read an array element: perform any pre-use barriers, calculate an effective address818* and perform the work.819* @param srcObject The array being used.820* @param srcIndex The element index821*/822void *823MM_ObjectAccessBarrier::indexableReadAddress(J9VMThread *vmThread, J9IndexableObject *srcObject, I_32 srcIndex, bool isVolatile)824{825void **actualAddress = (void **)indexableEffectiveAddress(vmThread, srcObject, srcIndex, sizeof(void *));826protectIfVolatileBefore(vmThread, isVolatile, true, false);827void *result = readAddressImpl(vmThread, (J9Object*)srcObject, actualAddress);828protectIfVolatileAfter(vmThread, isVolatile, true, false);829return result;830}831832/**833* Read an array element: perform any pre-use barriers, calculate an effective address834* and perform the work.835* @param srcObject The array being used.836* @param srcIndex The element index837*/838U_8839MM_ObjectAccessBarrier::indexableReadU8(J9VMThread *vmThread, J9IndexableObject *srcObject, I_32 srcIndex, bool isVolatile)840{841U_8 *actualAddress = (U_8 *)indexableEffectiveAddress(vmThread, srcObject, srcIndex, sizeof(U_8));842protectIfVolatileBefore(vmThread, isVolatile, true, false);843U_8 result = readU8Impl(vmThread, (mm_j9object_t)srcObject, actualAddress);844protectIfVolatileAfter(vmThread, isVolatile, true, false);845return result;846}847848/**849* Read an array element: perform any pre-use barriers, calculate an effective address850* and perform the work.851* @param srcObject The array being used.852* @param srcIndex The element index853*/854I_8855MM_ObjectAccessBarrier::indexableReadI8(J9VMThread *vmThread, J9IndexableObject *srcObject, I_32 srcIndex, bool isVolatile)856{857I_8 *actualAddress = (I_8 *)indexableEffectiveAddress(vmThread, srcObject, srcIndex, sizeof(I_8));858protectIfVolatileBefore(vmThread, isVolatile, true, false);859I_8 result = readI8Impl(vmThread, (mm_j9object_t)srcObject, actualAddress);860protectIfVolatileAfter(vmThread, isVolatile, true, false);861return result;862}863864/**865* Read an array element: perform any pre-use barriers, calculate an effective address866* and perform the work.867* @param srcObject The array being used.868* @param srcIndex The element index869*/870U_16871MM_ObjectAccessBarrier::indexableReadU16(J9VMThread *vmThread, J9IndexableObject *srcObject, I_32 srcIndex, bool isVolatile)872{873U_16 *actualAddress = (U_16 *)indexableEffectiveAddress(vmThread, srcObject, srcIndex,sizeof(U_16));874protectIfVolatileBefore(vmThread, isVolatile, true, false);875U_16 result = readU16Impl(vmThread, (mm_j9object_t)srcObject, actualAddress);876protectIfVolatileAfter(vmThread, isVolatile, true, false);877return result;878}879880/**881* Read an array element: perform any pre-use barriers, calculate an effective address882* and perform the work.883* @param srcObject The array being used.884* @param srcIndex The element index885*/886I_16887MM_ObjectAccessBarrier::indexableReadI16(J9VMThread *vmThread, J9IndexableObject *srcObject, I_32 srcIndex, bool isVolatile)888{889I_16 *actualAddress = (I_16 *)indexableEffectiveAddress(vmThread, srcObject, srcIndex, sizeof(I_16));890protectIfVolatileBefore(vmThread, isVolatile, true, false);891I_16 result = readI16Impl(vmThread, (mm_j9object_t)srcObject, actualAddress);892protectIfVolatileAfter(vmThread, isVolatile, true, false);893return result;894}895896/**897* Read an array element: perform any pre-use barriers, calculate an effective address898* and perform the work.899* @param srcObject The array being used.900* @param srcIndex The element index901*/902U_32903MM_ObjectAccessBarrier::indexableReadU32(J9VMThread *vmThread, J9IndexableObject *srcObject, I_32 srcIndex, bool isVolatile)904{905U_32 *actualAddress = (U_32 *)indexableEffectiveAddress(vmThread, srcObject, srcIndex, sizeof(U_32));906protectIfVolatileBefore(vmThread, isVolatile, true, false);907U_32 result = readU32Impl(vmThread, (mm_j9object_t)srcObject, actualAddress);908protectIfVolatileAfter(vmThread, isVolatile, true, false);909return result;910}911912/**913* Read an array element: perform any pre-use barriers, calculate an effective address914* and perform the work.915* @param srcObject The array being used.916* @param srcIndex The element index917*/918I_32919MM_ObjectAccessBarrier::indexableReadI32(J9VMThread *vmThread, J9IndexableObject *srcObject, I_32 srcIndex, bool isVolatile)920{921I_32 *actualAddress = (I_32 *)indexableEffectiveAddress(vmThread, srcObject, srcIndex, sizeof(I_32));922protectIfVolatileBefore(vmThread, isVolatile, true, false);923I_32 result = readI32Impl(vmThread, (mm_j9object_t)srcObject, actualAddress);924protectIfVolatileAfter(vmThread, isVolatile, true, false);925return result;926}927928/**929* Read an array element: perform any pre-use barriers, calculate an effective address930* and perform the work.931* @param srcObject The array being used.932* @param srcIndex The element index933*/934U_64935MM_ObjectAccessBarrier::indexableReadU64(J9VMThread *vmThread, J9IndexableObject *srcObject, I_32 srcIndex, bool isVolatile)936{937U_64 *actualAddress = (U_64 *)indexableEffectiveAddress(vmThread, srcObject, srcIndex, sizeof(U_64));938protectIfVolatileBefore(vmThread, isVolatile, true, true);939U_64 result = readU64Impl(vmThread, (mm_j9object_t)srcObject, actualAddress, isVolatile);940protectIfVolatileAfter(vmThread, isVolatile, true, true);941return result;942}943944/**945* Read an array element: perform any pre-use barriers, calculate an effective address946* and perform the work.947* @param srcObject The array being used.948* @param srcIndex The element index949*/950I_64951MM_ObjectAccessBarrier::indexableReadI64(J9VMThread *vmThread, J9IndexableObject *srcObject, I_32 srcIndex, bool isVolatile)952{953I_64 *actualAddress = (I_64 *)indexableEffectiveAddress(vmThread, srcObject, srcIndex, sizeof(I_64));954protectIfVolatileBefore(vmThread, isVolatile, true, true);955I_64 result = readI64Impl(vmThread, (mm_j9object_t)srcObject, actualAddress, isVolatile);956protectIfVolatileAfter(vmThread, isVolatile, true, true);957return result;958}959960961/**962* Store an array element: perform any pre-use barriers, calculate an effective address963* and perform the work.964* @param destObject The array being used.965* @param destIndex The element index966* @param value The value to store.967*/968void969MM_ObjectAccessBarrier::indexableStoreObject(J9VMThread *vmThread, J9IndexableObject *destObject, I_32 destIndex, J9Object *value, bool isVolatile)970{971UDATA const referenceSize = J9VMTHREAD_REFERENCE_SIZE(vmThread);972fj9object_t *actualAddress = (fj9object_t *)indexableEffectiveAddress(vmThread, destObject, destIndex, referenceSize);973974if (preObjectStore(vmThread, (J9Object *)destObject, actualAddress, value)) {975protectIfVolatileBefore(vmThread, isVolatile, false, false);976storeObjectImpl(vmThread, (J9Object*)destObject, actualAddress, value);977protectIfVolatileAfter(vmThread, isVolatile, false, false);978postObjectStore(vmThread, (J9Object *)destObject, actualAddress, value);979}980}981982/**983* Store an array element: perform any pre-use barriers, calculate an effective address984* and perform the work.985* @param destObject The array being used.986* @param destIndex The element index987* @param value The value to store.988*/989void990MM_ObjectAccessBarrier::indexableStoreAddress(J9VMThread *vmThread, J9IndexableObject *destObject, I_32 destIndex,void *value, bool isVolatile)991{992void **actualAddress = (void **)indexableEffectiveAddress(vmThread, destObject, destIndex, sizeof(void *));993protectIfVolatileBefore(vmThread, isVolatile, false, false);994storeAddressImpl(vmThread, (mm_j9object_t)destObject, actualAddress, value);995protectIfVolatileAfter(vmThread, isVolatile, false, false);996}997998/**999* Store an array element: perform any pre-use barriers, calculate an effective address1000* and perform the work.1001* @param destObject The array being used.1002* @param destIndex The element index1003* @param value The value to store.1004*/1005void1006MM_ObjectAccessBarrier::indexableStoreU8(J9VMThread *vmThread, J9IndexableObject *destObject, I_32 destIndex, U_8 value, bool isVolatile)1007{1008U_8 *actualAddress = (U_8 *)indexableEffectiveAddress(vmThread, destObject, destIndex, sizeof(U_8));1009protectIfVolatileBefore(vmThread, isVolatile, false, false);1010storeU8Impl(vmThread, (mm_j9object_t)destObject, actualAddress, value);1011protectIfVolatileAfter(vmThread, isVolatile, false, false);1012}10131014/**1015* Store an array element: perform any pre-use barriers, calculate an effective address1016* and perform the work.1017* @param destObject The array being used.1018* @param destIndex The element index1019* @param value The value to store.1020*/1021void1022MM_ObjectAccessBarrier::indexableStoreI8(J9VMThread *vmThread, J9IndexableObject *destObject, I_32 destIndex, I_8 value, bool isVolatile)1023{1024I_8 *actualAddress = (I_8 *)indexableEffectiveAddress(vmThread, destObject, destIndex, sizeof(I_8));1025protectIfVolatileBefore(vmThread, isVolatile, false, false);1026storeI8Impl(vmThread, (mm_j9object_t)destObject, actualAddress, value);1027protectIfVolatileAfter(vmThread, isVolatile, false, false);1028}10291030/**1031* Store an array element: perform any pre-use barriers, calculate an effective address1032* and perform the work.1033* @param destObject The array being used.1034* @param destIndex The element index1035* @param value The value to store.1036*/1037void1038MM_ObjectAccessBarrier::indexableStoreU16(J9VMThread *vmThread, J9IndexableObject *destObject, I_32 destIndex, U_16 value, bool isVolatile)1039{1040U_16 *actualAddress = (U_16 *)indexableEffectiveAddress(vmThread, destObject, destIndex, sizeof(U_16));1041protectIfVolatileBefore(vmThread, isVolatile, false, false);1042storeU16Impl(vmThread, (mm_j9object_t)destObject, actualAddress, value);1043protectIfVolatileAfter(vmThread, isVolatile, false, false);1044}10451046/**1047* Store an array element: perform any pre-use barriers, calculate an effective address1048* and perform the work.1049* @param destObject The array being used.1050* @param destIndex The element index1051* @param value The value to store.1052*/1053void1054MM_ObjectAccessBarrier::indexableStoreI16(J9VMThread *vmThread, J9IndexableObject *destObject, I_32 destIndex, I_16 value, bool isVolatile)1055{1056I_16 *actualAddress = (I_16 *)indexableEffectiveAddress(vmThread, destObject, destIndex, sizeof(I_16));1057protectIfVolatileBefore(vmThread, isVolatile, false, false);1058storeI16Impl(vmThread, (mm_j9object_t)destObject, actualAddress, value);1059protectIfVolatileAfter(vmThread, isVolatile, false, false);1060}10611062/**1063* Store an array element: perform any pre-use barriers, calculate an effective address1064* and perform the work.1065* @param destObject The array being used.1066* @param destIndex The element index1067* @param value The value to store.1068*/1069void1070MM_ObjectAccessBarrier::indexableStoreU32(J9VMThread *vmThread, J9IndexableObject *destObject, I_32 destIndex, U_32 value, bool isVolatile)1071{1072U_32 *actualAddress = (U_32 *)indexableEffectiveAddress(vmThread, destObject, destIndex, sizeof(U_32));1073protectIfVolatileBefore(vmThread, isVolatile, false, false);1074storeU32Impl(vmThread, (mm_j9object_t)destObject, actualAddress, value);1075protectIfVolatileAfter(vmThread, isVolatile, false, false);1076}10771078/**1079* Store an array element: perform any pre-use barriers, calculate an effective address1080* and perform the work.1081* @param destObject The array being used.1082* @param destIndex The element index1083* @param value The value to store.1084*/1085void1086MM_ObjectAccessBarrier::indexableStoreI32(J9VMThread *vmThread, J9IndexableObject *destObject, I_32 destIndex, I_32 value, bool isVolatile)1087{1088I_32 *actualAddress = (I_32 *)indexableEffectiveAddress(vmThread, destObject, destIndex, sizeof(I_32));1089protectIfVolatileBefore(vmThread, isVolatile, false, false);1090storeI32Impl(vmThread, (mm_j9object_t)destObject, actualAddress, value);1091protectIfVolatileAfter(vmThread, isVolatile, false, false);1092}10931094/**1095* Store an array element: perform any pre-use barriers, calculate an effective address1096* and perform the work.1097* @param destObject The array being used.1098* @param destIndex The element index1099* @param value The value to store.1100*/1101void1102MM_ObjectAccessBarrier::indexableStoreU64(J9VMThread *vmThread, J9IndexableObject *destObject, I_32 destIndex, U_64 value, bool isVolatile)1103{1104U_64 *actualAddress = (U_64 *)indexableEffectiveAddress(vmThread, destObject, destIndex, sizeof(U_64));1105protectIfVolatileBefore(vmThread, isVolatile, false, true);1106storeU64Impl(vmThread, (mm_j9object_t)destObject, actualAddress, value, isVolatile);1107protectIfVolatileAfter(vmThread, isVolatile, false, true);1108}11091110/**1111* Store an array element: perform any pre-use barriers, calculate an effective address1112* and perform the work.1113* @param destObject The array being used.1114* @param destIndex The element index1115* @param value The value to store.1116*/1117void1118MM_ObjectAccessBarrier::indexableStoreI64(J9VMThread *vmThread, J9IndexableObject *destObject, I_32 destIndex, I_64 value, bool isVolatile)1119{1120I_64 *actualAddress = (I_64 *)indexableEffectiveAddress(vmThread, destObject, destIndex, sizeof(I_64));1121protectIfVolatileBefore(vmThread, isVolatile, false, true);1122storeI64Impl(vmThread, (mm_j9object_t)destObject, actualAddress, value, isVolatile);1123protectIfVolatileAfter(vmThread, isVolatile, false, true);1124}11251126/**1127* Copy object fields into flattened array element1128*1129* @param vmThread thread token1130* @param arrayClazz array J9Class1131* @param srcObject object whose fields will be copied1132* @param arrayRef array object1133* @param index index of array element where fields are copied to1134*/1135void1136MM_ObjectAccessBarrier::copyObjectFieldsToFlattenedArrayElement(J9VMThread *vmThread, J9ArrayClass *arrayClazz, j9object_t srcObject, J9IndexableObject *arrayRef, I_32 index)1137{1138UDATA elementStartOffset = J9VMTHREAD_OBJECT_HEADER_SIZE(vmThread);1139U_8 *elementAddress = (U_8*)indexableEffectiveAddress(vmThread, arrayRef, index, J9ARRAYCLASS_GET_STRIDE((J9Class *) arrayClazz));1140IDATA elementOffset = (elementAddress - (U_8*)arrayRef);1141J9Class *elementClazz = J9GC_J9OBJECT_CLAZZ_THREAD(srcObject, vmThread);1142Assert_MM_true(J9_IS_J9CLASS_VALUETYPE(elementClazz));1143Assert_MM_true(elementClazz == arrayClazz->leafComponentType);11441145elementStartOffset += J9CLASS_PREPADDING_SIZE(elementClazz);11461147copyObjectFields(vmThread, elementClazz, srcObject, elementStartOffset, (j9object_t) arrayRef, elementOffset);1148}11491150/**1151* Copy object fields into flattened array element1152*1153* @param vmThread thread token1154* @param arrayClazz array J9Class1155* @param destObject object where array element fields will be copied to1156* @param arrayRef array object1157* @param index index of array element where fields are copied to1158*/1159void1160MM_ObjectAccessBarrier::copyObjectFieldsFromFlattenedArrayElement(J9VMThread *vmThread, J9ArrayClass *arrayClazz, j9object_t destObject, J9IndexableObject *arrayRef, I_32 index)1161{1162UDATA elementStartOffset = J9VMTHREAD_OBJECT_HEADER_SIZE(vmThread);1163U_8 *elementAddress = (U_8*)indexableEffectiveAddress(vmThread, arrayRef, index, J9ARRAYCLASS_GET_STRIDE((J9Class *) arrayClazz));1164IDATA elementOffset = (elementAddress - (U_8*)arrayRef);1165J9Class *elementClazz = J9GC_J9OBJECT_CLAZZ_THREAD(destObject, vmThread);1166Assert_MM_true(J9_IS_J9CLASS_VALUETYPE(elementClazz));1167Assert_MM_true(elementClazz == arrayClazz->leafComponentType);11681169elementStartOffset += J9CLASS_PREPADDING_SIZE(elementClazz);11701171copyObjectFields(vmThread, elementClazz, (j9object_t) arrayRef, elementOffset, destObject, elementStartOffset);1172}117311741175/**1176* Read a static field.1177* @param srcSlot The static field slot.1178* @param isVolatile non-zero if the field is volatile.1179*/1180J9Object *1181MM_ObjectAccessBarrier::staticReadObject(J9VMThread *vmThread, J9Class *clazz, J9Object **srcSlot, bool isVolatile)1182{1183J9Object *result = NULL;11841185if (preObjectRead(vmThread, clazz, srcSlot)) {1186protectIfVolatileBefore(vmThread, isVolatile, true, true);1187result = staticReadObjectImpl(vmThread, clazz, srcSlot, isVolatile);1188protectIfVolatileAfter(vmThread, isVolatile, true, true);11891190if (!postObjectRead(vmThread, clazz, srcSlot)) {1191result = NULL;1192}1193}11941195/* This must always be called to massage the return value */1196return result;1197}11981199/**1200* Read a static field.1201* @param srcSlot The static field slot.1202* @param isVolatile non-zero if the field is volatile.1203*/1204void *1205MM_ObjectAccessBarrier::staticReadAddress(J9VMThread *vmThread, J9Class *clazz, void **srcSlot, bool isVolatile)1206{1207protectIfVolatileBefore(vmThread, isVolatile, true, true);1208void *result = readAddressImpl(vmThread, NULL, srcSlot, isVolatile);1209protectIfVolatileAfter(vmThread, isVolatile, true, true);1210return result;1211}12121213/**1214* Read a static field.1215* @param srcSlot The static field slot.1216* @param isVolatile non-zero if the field is volatile.1217*/1218U_321219MM_ObjectAccessBarrier::staticReadU32(J9VMThread *vmThread, J9Class *clazz, U_32 *srcSlot, bool isVolatile)1220{1221protectIfVolatileBefore(vmThread, isVolatile, true, true);1222U_32 result = readU32Impl(vmThread, NULL, srcSlot, isVolatile);1223protectIfVolatileAfter(vmThread, isVolatile, true, true);1224return result;1225}12261227/**1228* Read a static field.1229* @param srcSlot The static field slot.1230* @param isVolatile non-zero if the field is volatile.1231*/1232I_321233MM_ObjectAccessBarrier::staticReadI32(J9VMThread *vmThread, J9Class *clazz, I_32 *srcSlot, bool isVolatile)1234{1235protectIfVolatileBefore(vmThread, isVolatile, true, true);1236I_32 result = readI32Impl(vmThread, NULL, srcSlot, isVolatile);1237protectIfVolatileAfter(vmThread, isVolatile, true, true);1238return result;1239}12401241/**1242* Read a static field.1243* @param srcSlot The static field slot.1244* @param isVolatile non-zero if the field is volatile.1245*/1246U_641247MM_ObjectAccessBarrier::staticReadU64(J9VMThread *vmThread, J9Class *clazz, U_64 *srcSlot, bool isVolatile)1248{1249protectIfVolatileBefore(vmThread, isVolatile, true, true);1250U_64 result = readU64Impl(vmThread, NULL, srcSlot, isVolatile);1251protectIfVolatileAfter(vmThread, isVolatile, true, true);1252return result;1253}12541255/**1256* Read a static field.1257* @param srcSlot The static field slot.1258* @param isVolatile non-zero if the field is volatile.1259*/1260I_641261MM_ObjectAccessBarrier::staticReadI64(J9VMThread *vmThread, J9Class *clazz, I_64 *srcSlot, bool isVolatile)1262{1263protectIfVolatileBefore(vmThread, isVolatile, true, true);1264I_64 result = readI64Impl(vmThread, NULL, srcSlot, isVolatile);1265protectIfVolatileAfter(vmThread, isVolatile, true, true);1266return result;1267}12681269/**1270* Store a static field.1271* @param destSlot The static slot being used.1272* @param value The value to be stored1273* @param isVolatile non-zero if the field is volatile.1274*/1275void1276MM_ObjectAccessBarrier::staticStoreObject(J9VMThread *vmThread, J9Class *clazz, J9Object **destSlot, J9Object *value, bool isVolatile)1277{1278j9object_t destObject = J9VM_J9CLASS_TO_HEAPCLASS(clazz);1279if (preObjectStore(vmThread, destObject, destSlot, value, isVolatile)) {1280protectIfVolatileBefore(vmThread, isVolatile, false, true);1281staticStoreObjectImpl(vmThread, clazz, destSlot, value, isVolatile);1282protectIfVolatileAfter(vmThread, isVolatile, false, true);12831284postObjectStore(vmThread, clazz, destSlot, value, isVolatile);1285}1286}12871288/**1289* Store a static field.1290* @param destSlot The static slot being used.1291* @param value The value to be stored1292* @param isVolatile non-zero if the field is volatile.1293*/1294void1295MM_ObjectAccessBarrier::staticStoreAddress(J9VMThread *vmThread, J9Class *clazz, void **destSlot,void *value, bool isVolatile)1296{1297protectIfVolatileBefore(vmThread, isVolatile, false, true);1298storeAddressImpl(vmThread, NULL, destSlot, value, isVolatile);1299protectIfVolatileAfter(vmThread, isVolatile, false, true);1300}13011302/**1303* Store a static field.1304* @param destSlot The static slot being used.1305* @param value The value to be stored1306* @param isVolatile non-zero if the field is volatile.1307*/1308void1309MM_ObjectAccessBarrier::staticStoreU32(J9VMThread *vmThread, J9Class *clazz, U_32 *destSlot, U_32 value, bool isVolatile)1310{1311protectIfVolatileBefore(vmThread, isVolatile, false, true);1312storeU32Impl(vmThread, NULL, destSlot, value, isVolatile);1313protectIfVolatileAfter(vmThread, isVolatile, false, true);1314}13151316/**1317* Store a static field.1318* @param destSlot The static slot being used.1319* @param value The value to be stored1320* @param isVolatile non-zero if the field is volatile.1321*/1322void1323MM_ObjectAccessBarrier::staticStoreI32(J9VMThread *vmThread, J9Class *clazz, I_32 *destSlot, I_32 value, bool isVolatile)1324{1325protectIfVolatileBefore(vmThread, isVolatile, false, true);1326storeI32Impl(vmThread, NULL, destSlot, value, isVolatile);1327protectIfVolatileAfter(vmThread, isVolatile, false, true);1328}13291330/**1331* Store a static field.1332* @param destSlot The static slot being used.1333* @param value The value to be stored1334* @param isVolatile non-zero if the field is volatile.1335*/1336void1337MM_ObjectAccessBarrier::staticStoreU64(J9VMThread *vmThread, J9Class *clazz, U_64 *destSlot, U_64 value, bool isVolatile)1338{1339protectIfVolatileBefore(vmThread, isVolatile, false, true);1340storeU64Impl(vmThread, NULL, destSlot, value, isVolatile);1341protectIfVolatileAfter(vmThread, isVolatile, false, true);1342}13431344/**1345* Store a static field.1346* @param destSlot The static slot being used.1347* @param value The value to be stored1348* @param isVolatile non-zero if the field is volatile.1349*/1350void1351MM_ObjectAccessBarrier::staticStoreI64(J9VMThread *vmThread, J9Class *clazz, I_64 *destSlot, I_64 value, bool isVolatile)1352{1353protectIfVolatileBefore(vmThread, isVolatile, false, true);1354storeI64Impl(vmThread, NULL, destSlot, value, isVolatile);1355protectIfVolatileAfter(vmThread, isVolatile, false, true);1356}13571358/**1359* Return a pointer to the first byte of an array's object data1360* @param arrayObject the base pointer of the array object1361*/1362U_8 *1363MM_ObjectAccessBarrier::getArrayObjectDataAddress(J9VMThread *vmThread, J9IndexableObject *arrayObject)1364{1365if (_extensions->indexableObjectModel.isInlineContiguousArraylet(arrayObject)) {1366return (U_8 *)_extensions->indexableObjectModel.getDataPointerForContiguous(arrayObject);1367} else {1368return (U_8 *)_extensions->indexableObjectModel.getArrayoidPointer(arrayObject);1369}1370}13711372/**1373* Return the address of the lockword for the given object, or NULL if it1374* does not have an inline lockword.1375*/1376j9objectmonitor_t *1377MM_ObjectAccessBarrier::getLockwordAddress(J9VMThread *vmThread, J9Object *object)1378{1379j9objectmonitor_t *lockwordAddress = NULL;1380J9Class *clazz = J9OBJECT_CLAZZ(vmThread, object);1381if (!J9_IS_J9CLASS_VALUETYPE(clazz)) {1382UDATA lockOffset = clazz->lockOffset;1383if ((IDATA) lockOffset >= 0) {1384lockwordAddress = (j9objectmonitor_t *)(((U_8 *)object) + lockOffset);1385}1386}1387return lockwordAddress;1388}13891390/**1391* Copy all of the fields of an object into another object.1392* The new object was just allocated inside the VM, so all fields are NULL.1393* @TODO This does not currently check if the fields that it is reading are volatile.1394*/1395void1396MM_ObjectAccessBarrier::cloneObject(J9VMThread *vmThread, J9Object *srcObject, J9Object *destObject)1397{1398UDATA elementStartOffset = J9VMTHREAD_OBJECT_HEADER_SIZE(vmThread);1399J9Class *cloneClazz = J9GC_J9OBJECT_CLAZZ_THREAD(srcObject, vmThread);14001401elementStartOffset += J9CLASS_PREPADDING_SIZE(cloneClazz);14021403copyObjectFields(vmThread, cloneClazz, srcObject, elementStartOffset, destObject, elementStartOffset);1404}14051406BOOLEAN1407MM_ObjectAccessBarrier::structuralCompareFlattenedObjects(J9VMThread *vmThread, J9Class *valueClass, j9object_t lhsObject, j9object_t rhsObject, UDATA startOffset)1408{1409bool result = true;1410bool const compressed = J9VMTHREAD_COMPRESS_OBJECT_REFERENCES(vmThread);1411UDATA const referenceSize = J9VMTHREAD_REFERENCE_SIZE(vmThread);1412bool hasReferences = J9CLASS_HAS_REFERENCES(valueClass);1413/* for non value-types this is just the instance size */1414UDATA limit = J9CLASS_UNPADDED_INSTANCE_SIZE(valueClass);1415UDATA offset = 0;14161417Assert_MM_true(J9_IS_J9CLASS_VALUETYPE(valueClass));14181419if (hasReferences) {1420UDATA descriptionIndex = J9_OBJECT_DESCRIPTION_SIZE - 1;1421const UDATA *descriptionPtr = (UDATA *) valueClass->instanceDescription;1422UDATA descriptionBits = 0;14231424if (((UDATA)descriptionPtr) & 1) {1425descriptionBits = ((UDATA)descriptionPtr) >> 1;1426} else {1427descriptionBits = *descriptionPtr++;1428}14291430while (offset < limit) {1431/* Determine if the slot contains an object pointer or not */1432if (descriptionBits & 1) {1433if (mixedObjectReadObject(vmThread, lhsObject, startOffset + offset, false) != mixedObjectReadObject(vmThread, rhsObject, startOffset + offset, false)) {1434result = false;1435break;1436}1437} else {1438fomrobject_t lhsValue = GC_SlotObject::readSlot((fomrobject_t*)((UDATA)lhsObject + startOffset + offset), compressed);1439fomrobject_t rhsValue = GC_SlotObject::readSlot((fomrobject_t*)((UDATA)rhsObject + startOffset + offset), compressed);1440if (lhsValue != rhsValue) {1441result = false;1442break;1443}1444}1445descriptionBits >>= 1;1446if (descriptionIndex-- == 0) {1447descriptionBits = *descriptionPtr++;1448descriptionIndex = J9_OBJECT_DESCRIPTION_SIZE - 1;1449}1450offset += referenceSize;1451}1452} else {1453/* no instanceDescription bits needed on this path */14541455while (offset < limit) {1456fomrobject_t lhsValue = GC_SlotObject::readSlot((fomrobject_t*)((UDATA)lhsObject + startOffset + offset), compressed);1457fomrobject_t rhsValue = GC_SlotObject::readSlot((fomrobject_t*)((UDATA)rhsObject + startOffset + offset), compressed);1458if (lhsValue != rhsValue) {1459result = false;1460break;1461}1462offset += referenceSize;1463}1464}14651466return result;1467}14681469/**1470* Copy all of the fields of a value class instance to another value class instance.1471* The source or destination may be a flattened value within another object, meaning1472* srcOffset and destOffset need not be equal. This is based on cloneObject(...). If1473* Type has pre-padding the size of the object will be adjusted to remove the padding1474* bytes. The caller of this API must ensure that the starting offset provided does1475* not include pre-padding.1476* @TODO This does not currently check if the fields that it is reading are volatile.1477*1478* @oaram objectClass The j9class.1479* @param srcObject The object containing the value class instance fields being copied.1480* @param srcOffset The offset of the value class instance fields in srcObject.1481* @param destValue The object containing the value class instance fields being copied to.1482* @param destOffset The offset of the value class instance fields in destObject.1483*/1484void1485MM_ObjectAccessBarrier::copyObjectFields(J9VMThread *vmThread, J9Class *objectClass, J9Object *srcObject, UDATA srcOffset, J9Object *destObject, UDATA destOffset)1486{1487/* For valueTypes we currently do not make a distinction between values that only contain1488* primitives and values that may contain a reference (ie. value vs mixed-value1489* in packedObject terminology). As a result, we will treat all values as if1490* they may contain references. In the future this may change.1491*1492* Value types have no need or lockwords, however, they are still present in the1493* current implementation. For now we will just skip over them by specifying1494* appropriate offsets. We will also skip over the bit in the instance description.1495*/1496bool isValueType = J9_IS_J9CLASS_VALUETYPE(objectClass);14971498j9objectmonitor_t *lockwordAddress = NULL;1499I_32 hashCode = 0;1500bool isDestObjectPreHashed = false;15011502if (!isValueType) {1503isDestObjectPreHashed = _extensions->objectModel.hasBeenHashed(destObject);1504if (isDestObjectPreHashed) {1505hashCode = _extensions->objectModel.getObjectHashCode(vmThread->javaVM, destObject);1506}1507}15081509UDATA offset = 0;1510/* for non value-types this is just the instance size */1511UDATA limit = J9CLASS_UNPADDED_INSTANCE_SIZE(objectClass);1512UDATA const referenceSize = J9VMTHREAD_REFERENCE_SIZE(vmThread);1513bool hasReferences = J9CLASS_HAS_REFERENCES(objectClass);15141515if (hasReferences) {1516const UDATA *descriptionPtr = (UDATA *) objectClass->instanceDescription;1517UDATA descriptionBits = 0;1518if (((UDATA)descriptionPtr) & 1) {1519descriptionBits = ((UDATA)descriptionPtr) >> 1;1520} else {1521descriptionBits = *descriptionPtr++;1522}15231524UDATA descriptionIndex = J9_OBJECT_DESCRIPTION_SIZE - 1;15251526while (offset < limit) {1527/* Determine if the slot contains an object pointer or not */1528if (descriptionBits & 1) {1529J9Object *objectPtr = mixedObjectReadObject(vmThread, srcObject, srcOffset + offset, false);1530mixedObjectStoreObject(vmThread, destObject, destOffset + offset, objectPtr, false);1531} else {1532UDATA srcAddress = (UDATA)srcObject + srcOffset + offset;1533UDATA destAddress = (UDATA)destObject + destOffset + offset;1534bool copy64Bits = false;1535UDATA descriptionBitsNext = descriptionBits;1536const UDATA *descriptionPtrNext = descriptionPtr;1537UDATA descriptionIndexNext = descriptionIndex;1538if (isValueType1539&& (sizeof(uint32_t) == referenceSize)1540&& (0 == (srcAddress & 7))1541&& ((offset + referenceSize) < limit)1542) {1543descriptionBitsNext >>= 1;1544if (descriptionIndexNext-- == 0) {1545descriptionBitsNext = *(descriptionPtrNext++);1546descriptionIndexNext = J9_OBJECT_DESCRIPTION_SIZE - 1;1547}1548if (0 == (descriptionBitsNext & 1)) {1549copy64Bits = true;1550}1551}1552if (copy64Bits) {1553*(uint64_t *)destAddress = *(uint64_t *)srcAddress;1554descriptionBits = descriptionBitsNext;1555descriptionPtr = descriptionPtrNext;1556descriptionIndex = descriptionIndexNext;1557/**1558* When doing 64-bit copy, offset needs to be advanced 8 bytes. referenceSize is 4 bytes here.1559* Advance offset 4 bytes here. Another 4 bytes are advanced at the end of the while loop below.1560*/1561offset += referenceSize;1562} else if (sizeof(uint32_t) == referenceSize) {1563*(uint32_t *)destAddress = *(uint32_t *)srcAddress;1564} else {1565*(uintptr_t *)destAddress = *(uintptr_t *)srcAddress;1566}1567}1568descriptionBits >>= 1;1569if (descriptionIndex-- == 0) {1570descriptionBits = *descriptionPtr++;1571descriptionIndex = J9_OBJECT_DESCRIPTION_SIZE - 1;1572}1573offset += referenceSize;1574}1575} else {1576/* no instanceDescription bits needed on this path */1577while (offset < limit) {1578UDATA srcAddress = (UDATA)srcObject + srcOffset + offset;1579UDATA destAddress = (UDATA)destObject + destOffset + offset;1580/* prefer to copy 64 bits at a time if possible */1581if ((sizeof(uint64_t) == referenceSize)1582|| (isValueType && (0 == (srcAddress & 7)) && ((offset + referenceSize) < limit))1583) {1584*(uint64_t *)destAddress = *(uint64_t *)srcAddress;1585offset += sizeof(uint64_t);1586} else {1587*(uint32_t *)destAddress = *(uint32_t *)srcAddress;1588offset += sizeof(uint32_t);1589}1590}1591}15921593if (!isValueType) {1594/* If an object was pre-hashed and a hash was stored within the fields of the object restore it.*/1595if (isDestObjectPreHashed) {1596UDATA hashcodeOffset = _extensions->mixedObjectModel.getHashcodeOffset(destObject);1597if (hashcodeOffset <= limit) {1598I_32 *hashcodePointer = (I_32*)((U_8*)destObject + hashcodeOffset);1599*hashcodePointer = hashCode;1600}1601}16021603/* initialize lockword, if present */1604lockwordAddress = getLockwordAddress(vmThread, destObject);1605if (NULL != lockwordAddress) {1606j9objectmonitor_t lwValue = VM_ObjectMonitor::getInitialLockword(vmThread->javaVM, objectClass);1607J9_STORE_LOCKWORD(vmThread, lockwordAddress, lwValue);1608}1609}1610}16111612/**1613* Copy all of the fields of an indexable object into another indexable object.1614* The new object was just allocated inside the VM, so all fields are NULL.1615* @TODO This does not currently check if the fields that it is reading are volatile.1616*/1617void1618MM_ObjectAccessBarrier::cloneIndexableObject(J9VMThread *vmThread, J9IndexableObject *srcObject, J9IndexableObject *destObject)1619{1620j9objectmonitor_t *lockwordAddress = NULL;1621bool isObjectArray = _extensions->objectModel.isObjectArray(srcObject);16221623if (_extensions->objectModel.hasBeenHashed((J9Object*)destObject)) {1624/* this assertion should never be triggered because we never pre-hash arrays */1625Assert_MM_unreachable();1626}16271628if (isObjectArray) {1629I_32 size = (I_32)_extensions->indexableObjectModel.getSizeInElements(srcObject);1630for (I_32 i = 0; i < size; i++) {1631J9Object *objectPtr = J9JAVAARRAYOFOBJECT_LOAD(vmThread, srcObject, i);1632J9JAVAARRAYOFOBJECT_STORE(vmThread, destObject, i, objectPtr);1633}1634} else {1635_extensions->indexableObjectModel.memcpyArray(destObject, srcObject);1636}16371638/* initialize lockword, if present */1639J9Class *objectClass = J9GC_J9OBJECT_CLAZZ_THREAD(destObject, vmThread);1640lockwordAddress = getLockwordAddress(vmThread, (J9Object*) destObject);1641if (NULL != lockwordAddress) {1642j9objectmonitor_t lwValue = VM_ObjectMonitor::getInitialLockword(vmThread->javaVM, objectClass);1643J9_STORE_LOCKWORD(vmThread, lockwordAddress, lwValue);1644}16451646return;1647}164816491650/* Return an j9object_t that can be stored in the constantpool.1651*1652* Not all collectors scan the constantpool on every GC and therefore for1653* these collectors the objects must be in tenure space.1654*1655* Note, the stack must be walkable as a GC may occur during this function.1656*1657* Note, this doesn't handle arrays.1658*1659* @param vmThread The current vmThread1660* @param toConvert The object to convert to a constantpool allowed form.1661*1662* @return an object that can be put in the constantpool or null if OOM.1663*/1664J9Object*1665MM_ObjectAccessBarrier::asConstantPoolObject(J9VMThread *vmThread, J9Object* toConvert, UDATA allocationFlags)1666{1667Assert_MM_true(allocationFlags & (J9_GC_ALLOCATE_OBJECT_TENURED | J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE));1668return toConvert;1669}16701671/**1672* Write an object to an internal VM slot (J9VMThread, J9JavaVM, named field of J9Class).1673* @param destSlot the slot to be used1674* @param value the value to be stored1675*/1676void1677MM_ObjectAccessBarrier::storeObjectToInternalVMSlot(J9VMThread *vmThread, J9Object** destSlot, J9Object *value)1678{1679if (preObjectStore(vmThread, destSlot, value, false)) {1680storeObjectToInternalVMSlotImpl(vmThread, destSlot, value, false);1681postObjectStore(vmThread, destSlot, value, false);1682}1683}16841685/**1686* Read an object from an internal VM slot (J9VMThread, J9JavaVM, named field of J9Class).1687* @param srcSlot the slot to be used1688*/1689J9Object *1690MM_ObjectAccessBarrier::readObjectFromInternalVMSlot(J9VMThread *vmThread, J9Object **srcSlot)1691{1692return readObjectFromInternalVMSlotImpl(vmThread, srcSlot, false);1693}16941695/**1696* compareAndSwapObject performs an atomic compare-and-swap on an object field or array element.1697* @param destObject the object containing the field being swapped into1698* @param destAddress the address of the destination field of the operation1699* @param compareObject the object to be compared with contents of destSlot1700* @param swapObject the object to be stored in the destSlot if compareObject is there now1701* @todo This should be converted to take the offset, not the address1702**/1703bool1704MM_ObjectAccessBarrier::compareAndSwapObject(J9VMThread *vmThread, J9Object *destObject, fj9object_t *destAddress, J9Object *compareObject, J9Object *swapObject)1705{1706fj9object_t *actualDestAddress;1707fj9object_t compareValue = convertTokenFromPointer(compareObject);1708fj9object_t swapValue = convertTokenFromPointer(swapObject);1709bool result = false;17101711/* TODO: To make this API more consistent, it should probably be split into separate1712* indexable and non-indexable versions. Currently, when called on an indexable object,1713* the REAL address is passed. For non-indexable objects, the address is the shadow1714* address1715*/1716if (_extensions->objectModel.isIndexable(destObject)) {1717actualDestAddress = destAddress;1718} else {1719actualDestAddress = J9OAB_MIXEDOBJECT_EA(destObject, ((UDATA)destAddress - (UDATA)destObject), fj9object_t);1720}17211722if (preObjectRead(vmThread, destObject, actualDestAddress)) {1723/* Note: This is a bit of a special case -- we call preObjectStore even though the store1724* may not actually occur. This is safe and correct for Metronome.1725*/1726preObjectStore(vmThread, destObject, actualDestAddress, swapObject, true);1727protectIfVolatileBefore(vmThread, true, false, false);17281729if (J9VMTHREAD_COMPRESS_OBJECT_REFERENCES(vmThread)) {1730result = ((U_32)(UDATA)compareValue == MM_AtomicOperations::lockCompareExchangeU32((U_32 *)actualDestAddress, (U_32)(UDATA)compareValue, (U_32)(UDATA)swapValue));1731} else {1732result = ((UDATA)compareValue == MM_AtomicOperations::lockCompareExchange((UDATA *)actualDestAddress, (UDATA)compareValue, (UDATA)swapValue));1733}1734protectIfVolatileAfter(vmThread, true, false, false);1735if (result) {1736postObjectStore(vmThread, destObject, actualDestAddress, swapObject, true);1737}1738}17391740return result;1741}17421743/**1744* staticCompareAndSwapObject performs an atomic compare-and-swap on a static object field.1745* @param destClass the class containing the statics field being swapped into1746* @param destAddress the address of the destination field of the operation1747* @param compareObject the object to be compared with contents of destSlot1748* @param swapObject the object to be stored in the destSlot if compareObject is there now1749* @todo This should be converted to take the offset, not the address1750**/1751bool1752MM_ObjectAccessBarrier::staticCompareAndSwapObject(J9VMThread *vmThread, J9Class *destClass, j9object_t *destAddress, J9Object *compareObject, J9Object *swapObject)1753{1754bool result = false;17551756if (preObjectRead(vmThread, destClass, destAddress)) {1757/* Note: This is a bit of a special case -- we call preObjectStore even though the store1758* may not actually occur. This is safe and correct for Metronome.1759*/1760preObjectStore(vmThread, (J9Object *)J9VM_J9CLASS_TO_HEAPCLASS(destClass), destAddress, swapObject, true);1761protectIfVolatileBefore(vmThread, true, false, false);17621763result = ((UDATA)compareObject == MM_AtomicOperations::lockCompareExchange((UDATA *)destAddress, (UDATA)compareObject, (UDATA)swapObject));17641765protectIfVolatileAfter(vmThread, true, false, false);1766if (result) {1767postObjectStore(vmThread, destClass, destAddress, swapObject, true);1768}1769}17701771return result;1772}17731774/**1775* Performs an atomic compare-and-swap on an int field of a mixed object1776* @param destObject the object containing the field being swapped into1777* @param destAddress the address of the destination field of the operation1778* @param compareValue the value to be compared with contents of destSlot1779* @param swapValue the value to be stored in the destSlot if compareValue is there now1780**/1781bool1782MM_ObjectAccessBarrier::mixedObjectCompareAndSwapInt(J9VMThread *vmThread, J9Object *destObject, UDATA offset, U_32 compareValue, U_32 swapValue)1783{1784U_32 *actualDestAddress = J9OAB_MIXEDOBJECT_EA(destObject, offset, U_32);17851786protectIfVolatileBefore(vmThread, true, false, false);1787bool result = (compareValue == MM_AtomicOperations::lockCompareExchangeU32(actualDestAddress, compareValue, swapValue));1788protectIfVolatileAfter(vmThread, true, false, false);1789return result;1790}17911792/**1793* Performs an atomic compare-and-swap on a static int field.1794* @param destClass the class containing the statics field being swapped into1795* @param destAddress the address of the destination field of the operation1796* @param compareValue the value to be compared with contents of destSlot1797* @param swapValue the value to be stored in the destSlot if compareValue is there now1798**/1799bool1800MM_ObjectAccessBarrier::staticCompareAndSwapInt(J9VMThread *vmThread, J9Class *destClass, U_32 *destAddress, U_32 compareValue, U_32 swapValue)1801{1802protectIfVolatileBefore(vmThread, true, false, false);1803bool result = (compareValue == MM_AtomicOperations::lockCompareExchangeU32(destAddress, compareValue, swapValue));1804protectIfVolatileAfter(vmThread, true, false, false);1805return result;1806}18071808/**1809* Performs an atomic compare-and-swap on an long field of a mixed object1810* @param destObject the object containing the field being swapped into1811* @param destAddress the address of the destination field of the operation1812* @param compareValue the value to be compared with contents of destSlot1813* @param swapValue the value to be stored in the destSlot if compareValue is there now1814**/1815bool1816MM_ObjectAccessBarrier::mixedObjectCompareAndSwapLong(J9VMThread *vmThread, J9Object *destObject, UDATA offset, U_64 compareValue, U_64 swapValue)1817{1818U_64 *actualDestAddress = J9OAB_MIXEDOBJECT_EA(destObject, offset, U_64);18191820protectIfVolatileBefore(vmThread, true, false, true);1821bool result = (compareValue == MM_AtomicOperations::lockCompareExchangeU64(actualDestAddress, compareValue, swapValue));1822protectIfVolatileAfter(vmThread, true, false, true);1823return result;1824}18251826/**1827* Performs an atomic compare-and-swap on a static long field.1828* @param destClass the class containing the statics field being swapped into1829* @param destAddress the address of the destination field of the operation1830* @param compareValue the value to be compared with contents of destSlot1831* @param swapValue the value to be stored in the destSlot if compareValue is there now1832**/1833bool1834MM_ObjectAccessBarrier::staticCompareAndSwapLong(J9VMThread *vmThread, J9Class *destClass, U_64 *destAddress, U_64 compareValue, U_64 swapValue)1835{1836protectIfVolatileBefore(vmThread, true, false, true);1837bool result = (compareValue == MM_AtomicOperations::lockCompareExchangeU64(destAddress, compareValue, swapValue));1838protectIfVolatileAfter(vmThread, true, false, true);1839return result;1840}18411842/**1843* Performs an atomic compare-and-exchange on an object field or array element.1844* @param destObject the object containing the field being swapped into1845* @param destAddress the address of the destination field of the operation1846* @param compareObject the object to be compared with contents of destSlot1847* @param swapObject the object to be stored in the destSlot if compareObject is there now1848* @return the object stored in the object field before the update1849* @todo This should be converted to take the offset, not the address1850**/1851J9Object *1852MM_ObjectAccessBarrier::compareAndExchangeObject(J9VMThread *vmThread, J9Object *destObject, fj9object_t *destAddress, J9Object *compareObject, J9Object *swapObject)1853{1854fj9object_t *actualDestAddress;1855fj9object_t compareValue = convertTokenFromPointer(compareObject);1856fj9object_t swapValue = convertTokenFromPointer(swapObject);1857J9Object *result = NULL;18581859/* TODO: To make this API more consistent, it should probably be split into separate1860* indexable and non-indexable versions. Currently, when called on an indexable object,1861* the REAL address is passed. For non-indexable objects, the address is the shadow1862* address1863*/1864if (_extensions->objectModel.isIndexable(destObject)) {1865actualDestAddress = destAddress;1866} else {1867actualDestAddress = J9OAB_MIXEDOBJECT_EA(destObject, ((UDATA)destAddress - (UDATA)destObject), fj9object_t);1868}18691870if (preObjectRead(vmThread, destObject, actualDestAddress)) {1871/* Note: This is a bit of a special case -- we call preObjectStore even though the store1872* may not actually occur. This is safe and correct for Metronome.1873*/1874preObjectStore(vmThread, destObject, actualDestAddress, swapObject, true);1875protectIfVolatileBefore(vmThread, true, false, false);18761877if (J9VMTHREAD_COMPRESS_OBJECT_REFERENCES(vmThread)) {1878result = (J9Object *)(UDATA)MM_AtomicOperations::lockCompareExchangeU32((U_32 *)actualDestAddress, (U_32)(UDATA)compareValue, (U_32)(UDATA)swapValue);1879} else {1880result = (J9Object *)MM_AtomicOperations::lockCompareExchange((UDATA *)actualDestAddress, (UDATA)compareValue, (UDATA)swapValue);1881}18821883protectIfVolatileAfter(vmThread, true, false, false);1884if (result) {1885postObjectStore(vmThread, destObject, actualDestAddress, swapObject, true);1886}1887}18881889return result;1890}18911892/**1893* Performs an atomic compare-and-exchange on a static object field.1894* @param destClass the class containing the statics field being swapped into1895* @param destAddress the address of the destination field of the operation1896* @param compareObject the object to be compared with contents of destSlot1897* @param swapObject the object to be stored in the destSlot if compareObject is there now1898* @return the object stored in the object field before the update1899* @todo This should be converted to take the offset, not the address1900**/1901J9Object *1902MM_ObjectAccessBarrier::staticCompareAndExchangeObject(J9VMThread *vmThread, J9Class *destClass, j9object_t *destAddress, J9Object *compareObject, J9Object *swapObject)1903{1904J9Object *result = NULL;19051906if (preObjectRead(vmThread, destClass, destAddress)) {1907/* Note: This is a bit of a special case -- we call preObjectStore even though the store1908* may not actually occur. This is safe and correct for Metronome.1909*/1910preObjectStore(vmThread, (J9Object *)J9VM_J9CLASS_TO_HEAPCLASS(destClass), destAddress, swapObject, true);1911protectIfVolatileBefore(vmThread, true, false, false);19121913result = (J9Object *)MM_AtomicOperations::lockCompareExchange((UDATA *)destAddress, (UDATA)compareObject, (UDATA)swapObject);19141915protectIfVolatileAfter(vmThread, true, false, false);1916if (result) {1917postObjectStore(vmThread, destClass, destAddress, swapObject, true);1918}1919}19201921return result;1922}19231924/**1925* Performs an atomic compare-and-exchange on an int field of a mixed object1926* @param destObject the object containing the field being swapped into1927* @param destAddress the address of the destination field of the operation1928* @param compareValue the value to be compared with contents of destSlot1929* @param swapValue the value to be stored in the destSlot if compareValue is there now1930* @return the int stored in the object field before the update1931**/1932U_321933MM_ObjectAccessBarrier::mixedObjectCompareAndExchangeInt(J9VMThread *vmThread, J9Object *destObject, UDATA offset, U_32 compareValue, U_32 swapValue)1934{1935U_32 *actualDestAddress = J9OAB_MIXEDOBJECT_EA(destObject, offset, U_32);19361937protectIfVolatileBefore(vmThread, true, false, false);1938U_32 result = MM_AtomicOperations::lockCompareExchangeU32(actualDestAddress, compareValue, swapValue);1939protectIfVolatileAfter(vmThread, true, false, false);1940return result;1941}19421943/**1944* Performs an atomic compare-and-exchange on a static int field.1945* @param destClass the class containing the statics field being swapped into1946* @param destAddress the address of the destination field of the operation1947* @param compareValue the value to be compared with contents of destSlot1948* @param swapValue the value to be stored in the destSlot if compareValue is there now1949* @return the int stored in the object field before the update1950**/1951U_321952MM_ObjectAccessBarrier::staticCompareAndExchangeInt(J9VMThread *vmThread, J9Class *destClass, U_32 *destAddress, U_32 compareValue, U_32 swapValue)1953{1954protectIfVolatileBefore(vmThread, true, false, false);1955U_32 result = MM_AtomicOperations::lockCompareExchangeU32(destAddress, compareValue, swapValue);1956protectIfVolatileAfter(vmThread, true, false, false);1957return result;1958}19591960/**1961* Performs an atomic compare-and-exchange on an long field of a mixed object1962* @param destObject the object containing the field being swapped into1963* @param destAddress the address of the destination field of the operation1964* @param compareValue the value to be compared with contents of destSlot1965* @param swapValue the value to be stored in the destSlot if compareValue is there now1966* @return the long stored in the object field before the update1967**/1968U_641969MM_ObjectAccessBarrier::mixedObjectCompareAndExchangeLong(J9VMThread *vmThread, J9Object *destObject, UDATA offset, U_64 compareValue, U_64 swapValue)1970{1971U_64 *actualDestAddress = J9OAB_MIXEDOBJECT_EA(destObject, offset, U_64);19721973protectIfVolatileBefore(vmThread, true, false, true);1974U_64 result = MM_AtomicOperations::lockCompareExchangeU64(actualDestAddress, compareValue, swapValue);1975protectIfVolatileAfter(vmThread, true, false, true);1976return result;1977}19781979/**1980* Performs an atomic compare-and-exchange on a static long field.1981* @param destClass the class containing the statics field being swapped into1982* @param destAddress the address of the destination field of the operation1983* @param compareValue the value to be compared with contents of destSlot1984* @param swapValue the value to be stored in the destSlot if compareValue is there now1985* @return the long stored in the object field before the update1986**/1987U_641988MM_ObjectAccessBarrier::staticCompareAndExchangeLong(J9VMThread *vmThread, J9Class *destClass, U_64 *destAddress, U_64 compareValue, U_64 swapValue)1989{1990protectIfVolatileBefore(vmThread, true, false, true);1991U_64 result = MM_AtomicOperations::lockCompareExchangeU64(destAddress, compareValue, swapValue);1992protectIfVolatileAfter(vmThread, true, false, true);1993return result;1994}19951996/**1997* Called before an object is stored into another object.1998* @return true if the store should proceed, false otherwise1999*/2000bool2001MM_ObjectAccessBarrier::preObjectStore(J9VMThread *vmThread, J9Object *destObject, fj9object_t *destAddress, J9Object *value, bool isVolatile)2002{2003return true;2004}20052006/**2007* Called before an object is stored into a class.2008* @return true if the store should proceed, false otherwise2009*/2010bool2011MM_ObjectAccessBarrier::preObjectStore(J9VMThread *vmThread, J9Object *destObject, J9Object **destAddress, J9Object *value, bool isVolatile)2012{2013return true;2014}20152016/**2017* Called before an object is stored into an internal VM structure.2018* @return true if the store should proceed, false otherwise2019*/2020bool2021MM_ObjectAccessBarrier::preObjectStore(J9VMThread *vmThread, J9Object **destAddress, J9Object *value, bool isVolatile)2022{2023return true;2024}20252026/**2027* Called after an object is stored into another object.2028*/2029void2030MM_ObjectAccessBarrier::postObjectStore(J9VMThread *vmThread, J9Object *destObject, fj9object_t *destAddress, J9Object *value, bool isVolatile)2031{2032}20332034/**2035* Called after an object is stored into a class.2036*/2037void2038MM_ObjectAccessBarrier::postObjectStore(J9VMThread *vmThread, J9Class *destObject, J9Object **destAddress, J9Object *value, bool isVolatile)2039{2040}20412042/**2043* Called after an object is stored into an internal VM structure.2044*/2045void2046MM_ObjectAccessBarrier::postObjectStore(J9VMThread *vmThread, J9Object **destAddress, J9Object *value, bool isVolatile)2047{2048}20492050/**2051* TODO: This should probably be postBatchObjectStore, not pre-.2052*/2053bool2054MM_ObjectAccessBarrier::postBatchObjectStore(J9VMThread *vmThread, J9Object *destObject, bool isVolatile)2055{2056#if defined(J9VM_GC_COMBINATION_SPEC)2057/* (assert here to verify that we aren't defaulting to this implementation through some unknown path - delete once combination is stable) */2058Assert_MM_unreachable();2059#endif /* defined(J9VM_GC_COMBINATION_SPEC) */2060return true;2061}20622063bool2064MM_ObjectAccessBarrier::postBatchObjectStore(J9VMThread *vmThread, J9Class *destClass, bool isVolatile)2065{2066#if defined(J9VM_GC_COMBINATION_SPEC)2067/* (assert here to verify that we aren't defaulting to this implementation through some unknown path - delete once combination is stable) */2068Assert_MM_unreachable();2069#endif /* defined(J9VM_GC_COMBINATION_SPEC) */2070return true;2071}20722073bool2074MM_ObjectAccessBarrier::preObjectRead(J9VMThread *vmThread, J9Object *srcObject, fj9object_t *srcAddress)2075{2076return true;2077}20782079bool2080MM_ObjectAccessBarrier::preWeakRootSlotRead(J9VMThread *vmThread, j9object_t *srcAddress)2081{2082return true;2083}20842085bool2086MM_ObjectAccessBarrier::preWeakRootSlotRead(J9JavaVM *vm, j9object_t *srcAddress)2087{2088return true;2089}209020912092bool2093MM_ObjectAccessBarrier::preObjectRead(J9VMThread *vmThread, J9Class *srcClass, J9Object **srcAddress)2094{2095return true;2096}20972098bool2099MM_ObjectAccessBarrier::postObjectRead(J9VMThread *vmThread, J9Object *srcObject, fj9object_t *srcAddress)2100{2101return true;2102}21032104bool2105MM_ObjectAccessBarrier::postObjectRead(J9VMThread *vmThread, J9Class *srcClass, J9Object **srcAddress)2106{2107return true;2108}21092110/**2111* Fills array (or part of array) with specific object value.2112* Example, compressed pointers access barrier will mangle the value2113* pointer before filling up the array with it.2114*/2115void2116MM_ObjectAccessBarrier::fillArrayOfObjects(J9VMThread *vmThread, j9array_t destObject, I_32 destIndex, I_32 count, j9object_t value)2117{2118#if defined(J9VM_GC_COMBINATION_SPEC)2119/* (assert here to verify that we aren't defaulting to this implementation through some unknown path - delete once combination is stable) */2120Assert_MM_unreachable();2121#endif /* defined(J9VM_GC_COMBINATION_SPEC) */2122if (J9VMTHREAD_COMPRESS_OBJECT_REFERENCES(vmThread)) {2123uint32_t *destPtr = (uint32_t *)indexableEffectiveAddress(vmThread, destObject, destIndex, sizeof(uint32_t));2124uint32_t actualValue = (uint32_t)convertTokenFromPointer(value);2125uint32_t *endPtr = destPtr + count;21262127while (destPtr < endPtr) {2128*destPtr++ = actualValue;2129}2130} else {2131uintptr_t *destPtr = (uintptr_t *)indexableEffectiveAddress(vmThread, destObject, destIndex, sizeof(uintptr_t));2132uintptr_t actualValue = (uintptr_t)convertTokenFromPointer(value);2133uintptr_t *endPtr = destPtr + count;21342135while (destPtr < endPtr) {2136*destPtr++ = actualValue;2137}2138}2139}21402141/**2142* Returns the shadow heap base for compressed pointers.2143* Used by the JIT in the interim solution until we store J9 class objects2144* on the heap.2145* @return shadow heap base.2146*/2147UDATA2148MM_ObjectAccessBarrier::compressedPointersShadowHeapBase(J9VMThread *vmThread)2149{2150assume0(false);2151return 0;2152}21532154/**2155* Returns the shadow heap base for compressed pointers.2156* Used by the JIT in the interim solution until we store J9 class objects2157* on the heap.2158* @return shadow heap top.2159*/2160UDATA2161MM_ObjectAccessBarrier::compressedPointersShadowHeapTop(J9VMThread *vmThread)2162{2163assume0(false);2164return 0;2165}21662167/**2168* @return this cannot fail (overloaded can) => returns ARRAY_COPY_NOT_DONE2169*/2170I_322171MM_ObjectAccessBarrier::doCopyContiguousBackward(J9VMThread *vmThread, J9IndexableObject *srcObject, J9IndexableObject *destObject, I_32 srcIndex, I_32 destIndex, I_32 lengthInSlots)2172{2173srcIndex += lengthInSlots;2174destIndex += lengthInSlots;21752176if (J9VMTHREAD_COMPRESS_OBJECT_REFERENCES(vmThread)) {2177uint32_t *srcSlot = (uint32_t *)indexableEffectiveAddress(vmThread, srcObject, srcIndex, sizeof(uint32_t));2178uint32_t *destSlot = (uint32_t *)indexableEffectiveAddress(vmThread, destObject, destIndex, sizeof(uint32_t));2179uint32_t *srcEndSlot = srcSlot - lengthInSlots;21802181while (srcSlot > srcEndSlot) {2182*--destSlot = *--srcSlot;2183}2184} else {2185uintptr_t *srcSlot = (uintptr_t *)indexableEffectiveAddress(vmThread, srcObject, srcIndex, sizeof(uintptr_t));2186uintptr_t *destSlot = (uintptr_t *)indexableEffectiveAddress(vmThread, destObject, destIndex, sizeof(uintptr_t));2187uintptr_t *srcEndSlot = srcSlot - lengthInSlots;21882189while (srcSlot > srcEndSlot) {2190*--destSlot = *--srcSlot;2191}2192}21932194return ARRAY_COPY_SUCCESSFUL;2195}21962197/**2198* @return this cannot fail (overloaded can) => returns ARRAY_COPY_NOT_DONE2199*/2200I_322201MM_ObjectAccessBarrier::doCopyContiguousForward(J9VMThread *vmThread, J9IndexableObject *srcObject, J9IndexableObject *destObject, I_32 srcIndex, I_32 destIndex, I_32 lengthInSlots)2202{2203if (J9VMTHREAD_COMPRESS_OBJECT_REFERENCES(vmThread)) {2204uint32_t *srcSlot = (uint32_t *)indexableEffectiveAddress(vmThread, srcObject, srcIndex, sizeof(uint32_t));2205uint32_t *destSlot = (uint32_t *)indexableEffectiveAddress(vmThread, destObject, destIndex, sizeof(uint32_t));2206uint32_t *srcEndSlot = srcSlot + lengthInSlots;22072208while (srcSlot < srcEndSlot) {2209*destSlot++ = *srcSlot++;2210}2211} else {2212uintptr_t *srcSlot = (uintptr_t *)indexableEffectiveAddress(vmThread, srcObject, srcIndex, sizeof(uintptr_t));2213uintptr_t *destSlot = (uintptr_t *)indexableEffectiveAddress(vmThread, destObject, destIndex, sizeof(uintptr_t));2214uintptr_t *srcEndSlot = srcSlot + lengthInSlots;22152216while (srcSlot < srcEndSlot) {2217*destSlot++ = *srcSlot++;2218}2219}22202221return ARRAY_COPY_SUCCESSFUL;2222}22232224I_322225MM_ObjectAccessBarrier::getObjectHashCode(J9JavaVM *vm, J9Object *object)2226{2227return _extensions->objectModel.getObjectHashCode(vm, object);2228}22292230void2231MM_ObjectAccessBarrier::setFinalizeLink(j9object_t object, j9object_t value)2232{2233fj9object_t* finalizeLink = getFinalizeLinkAddress(object);2234GC_SlotObject slot(_extensions->getOmrVM(), finalizeLink);2235slot.writeReferenceToSlot(value);2236}22372238void2239MM_ObjectAccessBarrier::setReferenceLink(j9object_t object, j9object_t value)2240{2241Assert_MM_true(NULL != object);2242UDATA linkOffset = _referenceLinkOffset;2243/* offset will be UDATA_MAX until java/lang/ref/Reference is loaded */2244Assert_MM_true(UDATA_MAX != linkOffset);2245fj9object_t *referenceLink = (fj9object_t*)((UDATA)object + linkOffset);2246GC_SlotObject slot(_extensions->getOmrVM(), referenceLink);2247slot.writeReferenceToSlot(value);2248}22492250void2251MM_ObjectAccessBarrier::setOwnableSynchronizerLink(j9object_t object, j9object_t value)2252{2253Assert_MM_true(NULL != object);2254UDATA linkOffset = _ownableSynchronizerLinkOffset;2255/* offset will be UDATA_MAX until java/util/concurrent/locks/AbstractOwnableSynchronizer is loaded */2256Assert_MM_true(UDATA_MAX != linkOffset);2257if (NULL == value) {2258/* set the last object in the list pointing to itself */2259value = object;2260}2261fj9object_t *ownableSynchronizerLink = (fj9object_t*)((UDATA)object + linkOffset);2262GC_SlotObject slot(_extensions->getOmrVM(), ownableSynchronizerLink);2263slot.writeReferenceToSlot(value);2264}22652266void2267MM_ObjectAccessBarrier::printNativeMethod(J9VMThread* vmThread)2268{2269J9SFJNINativeMethodFrame *nativeMethodFrame = VM_VMHelpers::findNativeMethodFrame(vmThread);2270J9Method *method = nativeMethodFrame->method;2271J9JavaVM *javaVM = vmThread->javaVM;2272PORT_ACCESS_FROM_JAVAVM(javaVM);22732274if (NULL != method) {2275J9UTF8 * className = J9ROMCLASS_CLASSNAME(J9_CP_FROM_METHOD(method)->ramClass->romClass);2276J9ROMMethod * romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(method);2277J9UTF8 * name = J9ROMMETHOD_NAME(romMethod);2278J9UTF8 * sig = J9ROMMETHOD_SIGNATURE(romMethod);22792280j9tty_printf(PORTLIB, "%p: Native Method %p (%.*s.%.*s%.*s)\n",2281vmThread, method,2282(U_32) J9UTF8_LENGTH(className), J9UTF8_DATA(className), (U_32) J9UTF8_LENGTH(name), J9UTF8_DATA(name), (U_32) J9UTF8_LENGTH(sig), J9UTF8_DATA(sig));22832284Trc_MM_ObjectAccessBarrier_printNativeMethod(vmThread, method,2285(U_32) J9UTF8_LENGTH(className), J9UTF8_DATA(className), (U_32) J9UTF8_LENGTH(name), J9UTF8_DATA(name), (U_32) J9UTF8_LENGTH(sig), J9UTF8_DATA(sig));2286} else {2287j9tty_printf(PORTLIB, "%p: Native Method Unknown\n", vmThread);2288Trc_MM_ObjectAccessBarrier_printNativeMethodUnknown(vmThread);2289}2290}22912292229322942295