Path: blob/master/runtime/gc_modron_startup/arrayCopy.cpp
5986 views
/*******************************************************************************1* Copyright (c) 1991, 2019 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_Modron_Base26*/2728#include "j9.h"29#include "j9protos.h"30#include "j9consts.h"31#include "j9cfg.h"32#include "modronopt.h"33#include "j9modron.h"34#include "arrayCopyInterface.h"35#include "ModronAssertions.h"3637#include <string.h>3839#include "EnvironmentBase.hpp"40#include "GCExtensions.hpp"41#include "ObjectAccessBarrier.hpp"42#include "ObjectModel.hpp"43#include "SlotObject.hpp"4445extern "C" {4647/**48* Called from JIT to determine how reference array copy should be handled.49* @return true if jitted code should always call the C helper for a reference array copy50* @return false otherwise51*/52UDATA53alwaysCallReferenceArrayCopyHelper(J9JavaVM *javaVM)54{55return MM_GCExtensions::getExtensions(javaVM)->isMetronomeGC() ? 1 : 0;56}5758/**59* Internal helper for performing a type check before an array store.60* @return true if the store is legal, false otherwise61* @note Translated from builder: J9VM>>typeCheckArrayStoreOf:into:ifFail:nullCheck:62*/63static bool64typeCheckArrayStore(J9VMThread *vmThread, J9Object *object, J9IndexableObject *arrayObj)65{66if (object) {67J9Class *componentType = ((J9ArrayClass *)J9OBJECT_CLAZZ(vmThread, arrayObj))->componentType;68/* Check if we are storing the object into an array of the same type */69J9Class *storedClazz = J9OBJECT_CLAZZ(vmThread, object);70if (storedClazz != componentType) {71/* Check if we are storing the object into an array of Object[] */72UDATA classDepth = J9CLASS_DEPTH(componentType);73if (classDepth != 0) {74return (0 != instanceOfOrCheckCast(storedClazz, componentType));75}76}77}78return true;79}8081/**82* Internal helper to see whether any type checks need to be performed during arraycopy.83* @return true if type checks should be performed, false otherwise.84*/85static MMINLINE bool86arrayStoreCheckRequired(J9VMThread *vmThread, J9IndexableObject *destObject, J9IndexableObject *srcObject)87{88J9Class *srcClazz = J9OBJECT_CLAZZ(vmThread, srcObject);89J9Class *destClazz = J9OBJECT_CLAZZ(vmThread, destObject);9091/* Type checks are not required only if both classes are the same, or92* the source class is a subclass of the dest class93*/94if (srcClazz != destClazz) {95UDATA srcDepth = J9CLASS_DEPTH(srcClazz);96UDATA destDepth = J9CLASS_DEPTH(destClazz);97if ((srcDepth <= destDepth) || (destClazz->superclasses[srcDepth] != srcClazz)) {98return true;99}100}101102return false;103}104105/**106* VM helper for performing a reference array copy.107* This function corresponds to the function of the same name in the memory manager108* function table. This helper is called by the System.arraycopy native when performing109* a reference array copy, after bounds checks have been made.110* This specific API takes starting positions in a form of address of a slot. It would just calculate111* corresponding starting indices and pass the request to referenceArrayCopyIndex() API.112* This API must be used only with contiguous arrays.113* @return -1 if the copy succeeded114* @return the index where the ArrayStoreException occurred, if the copy failed115*/116I_32117referenceArrayCopy(J9VMThread *vmThread, J9IndexableObject *srcObject, J9IndexableObject *destObject, fj9object_t *srcAddress, fj9object_t *destAddress, I_32 lengthInSlots)118{119if (lengthInSlots > 0) {120MM_GCExtensions *ext = MM_GCExtensions::getExtensions(vmThread->javaVM);121122Assert_MM_true(ext->indexableObjectModel.isInlineContiguousArraylet(srcObject) && ext->indexableObjectModel.isInlineContiguousArraylet(destObject));123124uintptr_t srcHeaderSize = ext->indexableObjectModel.getHeaderSize(srcObject);125uintptr_t destHeaderSize = ext->indexableObjectModel.getHeaderSize(destObject);126uintptr_t const referenceSize = J9VMTHREAD_REFERENCE_SIZE(vmThread);127I_32 srcIndex = (I_32)(((uintptr_t)srcAddress - (srcHeaderSize + (uintptr_t)srcObject)) / referenceSize);128I_32 destIndex = (I_32)(((uintptr_t)destAddress - (destHeaderSize + (uintptr_t)destObject)) / referenceSize);129130return referenceArrayCopyIndex(vmThread, srcObject, destObject, srcIndex, destIndex, lengthInSlots);131}132return -1;133134}135136/**137* VM helper for performing a reference array copy.138* This function corresponds to the function of the same name in the memory manager139* function table. This helper is called by the System.arraycopy native when performing140* a reference array copy, after bounds checks have been made.141* @return -1 if the copy succeeded142* @return if the copy failed, return the index where the exception occurred. It143* may be an ArrayStoreException144*/145I_32146referenceArrayCopyIndex(J9VMThread *vmThread, J9IndexableObject *srcObject, J9IndexableObject *destObject, I_32 srcIndex, I_32 destIndex, I_32 lengthInSlots)147{148if (lengthInSlots > 0) {149150J9WriteBarrierType wrtbarType = (J9WriteBarrierType)j9gc_modron_getWriteBarrierType(vmThread->javaVM);151J9ReferenceArrayCopyTable *table = &MM_GCExtensions::getExtensions(vmThread->javaVM)->referenceArrayCopyTable;152153if ((srcObject == destObject) && (srcIndex < destIndex) && ((srcIndex + lengthInSlots) > destIndex)) {154return table->backwardReferenceArrayCopyIndex[wrtbarType](vmThread, srcObject, destObject, srcIndex, destIndex, lengthInSlots);155}156if (arrayStoreCheckRequired(vmThread, destObject, srcObject)) {157return table->forwardReferenceArrayCopyWithCheckIndex[wrtbarType](vmThread, srcObject, destObject, srcIndex, destIndex, lengthInSlots);158}159return table->forwardReferenceArrayCopyWithoutCheckIndex[wrtbarType](vmThread, srcObject, destObject, srcIndex, destIndex, lengthInSlots);160}161return -1;162}163164I_32165backwardReferenceArrayCopyAndAlwaysWrtbarIndex(J9VMThread *vmThread, J9IndexableObject *srcObject, J9IndexableObject *destObject, I_32 srcIndex, I_32 destIndex, I_32 lengthInSlots)166{167MM_ObjectAccessBarrier *barrier = MM_GCExtensions::getExtensions(vmThread->javaVM)->accessBarrier;168I_32 result;169170/* Let access barrier specific code try doing an optimized version of the copy (if such exists) */171/* -1 copy successful, -2 no copy done, >=0 copy was attempted but and exception was raised (index returned) */172if (-1 <= (result = barrier->backwardReferenceArrayCopyIndex(vmThread, srcObject, destObject, srcIndex, destIndex, lengthInSlots))) {173return result;174}175176I_32 endSrcIndex = srcIndex;177J9Object *copyObject = NULL;178179srcIndex += lengthInSlots;180destIndex += lengthInSlots;181while(srcIndex > endSrcIndex) {182srcIndex--;183destIndex--;184copyObject = J9JAVAARRAYOFOBJECT_LOAD(vmThread, srcObject, srcIndex);185J9JAVAARRAYOFOBJECT_STORE(vmThread, destObject, destIndex, copyObject);186}187188return -1;189}190191I_32192forwardReferenceArrayCopyWithCheckAndAlwaysWrtbarIndex(J9VMThread *vmThread, J9IndexableObject *srcObject, J9IndexableObject *destObject, I_32 srcIndex, I_32 destIndex, I_32 lengthInSlots)193{194I_32 srcEndIndex = srcIndex + lengthInSlots;195196while (srcIndex < srcEndIndex) {197J9Object *copyObject = J9JAVAARRAYOFOBJECT_LOAD(vmThread, srcObject, srcIndex);198if (!typeCheckArrayStore(vmThread, copyObject, destObject)) {199goto error;200}201J9JAVAARRAYOFOBJECT_STORE(vmThread, destObject, destIndex, copyObject);202srcIndex++;203destIndex++;204}205206return -1;207208error:209return srcIndex;210}211212I_32213forwardReferenceArrayCopyWithoutCheckAndAlwaysWrtbarIndex(J9VMThread *vmThread, J9IndexableObject *srcObject, J9IndexableObject *destObject, I_32 srcIndex, I_32 destIndex, I_32 lengthInSlots)214{215MM_ObjectAccessBarrier *barrier = MM_GCExtensions::getExtensions(vmThread->javaVM)->accessBarrier;216I_32 result;217218/* Let access barrier specific code try doing an optimized version of the copy (if such exists) */219/* -1 copy successful, -2 no copy done, >=0 copy was attempted but and exception was raised (index returned) */220if (-1 <= (result = barrier->forwardReferenceArrayCopyIndex(vmThread, srcObject, destObject, srcIndex, destIndex, lengthInSlots))) {221return result;222}223224I_32 srcEndIndex = srcIndex + lengthInSlots;225226while (srcIndex < srcEndIndex) {227J9Object *copyObject = J9JAVAARRAYOFOBJECT_LOAD(vmThread, srcObject, srcIndex);228J9JAVAARRAYOFOBJECT_STORE(vmThread, destObject, destIndex, copyObject);229srcIndex++;230destIndex++;231}232233return -1;234}235236/**237* Error stub for function table entries that aren't needed by Metronome.238*/239I_32240copyVariantUndefinedIndex(J9VMThread *vmThread, J9IndexableObject *srcObject, J9IndexableObject *destObject, I_32 srcIndex, I_32 destIndex, I_32 lengthInSlots)241{242Assert_MM_unreachable();243return srcIndex;244}245246/**247* Initialize the reference array copy function table with the appropriate function pointers248* @note This table must be updated if @ref J9WriteBarrierType is changed249*/250void251initializeReferenceArrayCopyTable(J9ReferenceArrayCopyTable *table)252{253/* The generic reference array copy */254table->referenceArrayCopyIndex = referenceArrayCopyIndex;255256/* Backward copy doesn't require a type check, but source and dest object are the same */257table->backwardReferenceArrayCopyIndex[j9gc_modron_wrtbar_illegal] = copyVariantUndefinedIndex;258table->backwardReferenceArrayCopyIndex[j9gc_modron_wrtbar_none] = backwardReferenceArrayCopyAndAlwaysWrtbarIndex;259table->backwardReferenceArrayCopyIndex[j9gc_modron_wrtbar_always] = backwardReferenceArrayCopyAndAlwaysWrtbarIndex;260table->backwardReferenceArrayCopyIndex[j9gc_modron_wrtbar_oldcheck] = backwardReferenceArrayCopyAndAlwaysWrtbarIndex;261table->backwardReferenceArrayCopyIndex[j9gc_modron_wrtbar_cardmark] = backwardReferenceArrayCopyAndAlwaysWrtbarIndex;262table->backwardReferenceArrayCopyIndex[j9gc_modron_wrtbar_cardmark_incremental] = backwardReferenceArrayCopyAndAlwaysWrtbarIndex;263table->backwardReferenceArrayCopyIndex[j9gc_modron_wrtbar_cardmark_and_oldcheck] = backwardReferenceArrayCopyAndAlwaysWrtbarIndex;264table->backwardReferenceArrayCopyIndex[j9gc_modron_wrtbar_satb] = backwardReferenceArrayCopyAndAlwaysWrtbarIndex;265266/* Forward copies with type check on each element (check for ArrayStoreException) */267table->forwardReferenceArrayCopyWithCheckIndex[j9gc_modron_wrtbar_illegal] = copyVariantUndefinedIndex;268table->forwardReferenceArrayCopyWithCheckIndex[j9gc_modron_wrtbar_none] = forwardReferenceArrayCopyWithCheckAndAlwaysWrtbarIndex;269table->forwardReferenceArrayCopyWithCheckIndex[j9gc_modron_wrtbar_always] = forwardReferenceArrayCopyWithCheckAndAlwaysWrtbarIndex;270table->forwardReferenceArrayCopyWithCheckIndex[j9gc_modron_wrtbar_oldcheck] = forwardReferenceArrayCopyWithCheckAndAlwaysWrtbarIndex;271table->forwardReferenceArrayCopyWithCheckIndex[j9gc_modron_wrtbar_cardmark] = forwardReferenceArrayCopyWithCheckAndAlwaysWrtbarIndex;272table->forwardReferenceArrayCopyWithCheckIndex[j9gc_modron_wrtbar_cardmark_incremental] = forwardReferenceArrayCopyWithCheckAndAlwaysWrtbarIndex;273table->forwardReferenceArrayCopyWithCheckIndex[j9gc_modron_wrtbar_cardmark_and_oldcheck] = forwardReferenceArrayCopyWithCheckAndAlwaysWrtbarIndex;274table->forwardReferenceArrayCopyWithCheckIndex[j9gc_modron_wrtbar_satb] = forwardReferenceArrayCopyWithCheckAndAlwaysWrtbarIndex;275276/* Forward copies with no type check */277table->forwardReferenceArrayCopyWithoutCheckIndex[j9gc_modron_wrtbar_illegal] = copyVariantUndefinedIndex;278table->forwardReferenceArrayCopyWithoutCheckIndex[j9gc_modron_wrtbar_none] = forwardReferenceArrayCopyWithoutCheckAndAlwaysWrtbarIndex;279table->forwardReferenceArrayCopyWithoutCheckIndex[j9gc_modron_wrtbar_always] = forwardReferenceArrayCopyWithoutCheckAndAlwaysWrtbarIndex;280table->forwardReferenceArrayCopyWithoutCheckIndex[j9gc_modron_wrtbar_oldcheck] = forwardReferenceArrayCopyWithoutCheckAndAlwaysWrtbarIndex;281table->forwardReferenceArrayCopyWithoutCheckIndex[j9gc_modron_wrtbar_cardmark] = forwardReferenceArrayCopyWithoutCheckAndAlwaysWrtbarIndex;282table->forwardReferenceArrayCopyWithoutCheckIndex[j9gc_modron_wrtbar_cardmark_incremental] = forwardReferenceArrayCopyWithoutCheckAndAlwaysWrtbarIndex;283table->forwardReferenceArrayCopyWithoutCheckIndex[j9gc_modron_wrtbar_cardmark_and_oldcheck] = forwardReferenceArrayCopyWithoutCheckAndAlwaysWrtbarIndex;284table->forwardReferenceArrayCopyWithoutCheckIndex[j9gc_modron_wrtbar_satb] = forwardReferenceArrayCopyWithoutCheckAndAlwaysWrtbarIndex;285}286287} /* extern "C" */288289290