Path: blob/master/runtime/compiler/codegen/CodeGenGC.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2000, 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*******************************************************************************/2122#if defined(J9ZOS390)23//On zOS XLC linker can't handle files with same name at link time24//This workaround with pragma is needed. What this does is essentially25//give a different name to the codesection (csect) for this file. So it26//doesn't conflict with another file with same name.2728#pragma csect(CODE,"TRJ9CGGCBase#C")29#pragma csect(STATIC,"TRJ9CGGCBase#S")30#pragma csect(TEST,"TRJ9CGGCBase#T")31#endif3233#include "codegen/J9CodeGenerator.hpp" // IWYU pragma: keep3435#include <stdint.h>36#include <string.h>37#include "env/StackMemoryRegion.hpp"38#include "codegen/CodeGenerator.hpp"39#include "codegen/CodeGenerator_inlines.hpp"40#include "codegen/GCStackAtlas.hpp"41#include "codegen/GCStackMap.hpp"42#include "codegen/Linkage.hpp"43#include "codegen/Linkage_inlines.hpp"44#include "compile/Compilation.hpp"45#include "control/Options.hpp"46#include "control/Options_inlines.hpp"47#include "env/ObjectModel.hpp"48#include "env/CompilerEnv.hpp"49#include "env/TRMemory.hpp"50#include "env/jittypes.h"51#include "il/AutomaticSymbol.hpp"52#include "il/Node.hpp"53#include "il/ParameterSymbol.hpp"54#include "il/ResolvedMethodSymbol.hpp"55#include "il/Symbol.hpp"56#include "il/SymbolReference.hpp"57#include "infra/Assert.hpp"58#include "infra/BitVector.hpp"59#include "infra/IGNode.hpp"60#include "infra/InterferenceGraph.hpp"61#include "infra/List.hpp"62#include "ras/Debug.hpp"6364void65J9::CodeGenerator::createStackAtlas()66{67// Assign a GC map index to each reference parameter and each reference local.68// Stack mapping will have to map the stack in a way that honours these indices69//70TR::Compilation *comp = self()->comp();71TR::ResolvedMethodSymbol * methodSymbol = comp->getMethodSymbol();7273const bool doLocalsCompaction = self()->getLocalsIG() && self()->getSupportsCompactedLocals();7475// From hereon, any stack memory allocations will expire / die when the function returns76//77TR::StackMemoryRegion stackMemoryRegion(*self()->trMemory());7879// --------------------------------------------------------------------------------80// First map the parameters - the mapping of parameters is constrained by81// the linkage, so we depend on whether the linkage maps the parameters82// right to left or left to right.83// We assume that the parameters are mapped contiguously84//85ListIterator<TR::ParameterSymbol> parameterIterator(&methodSymbol->getParameterList());86TR::ParameterSymbol *parmCursor;8788intptr_t stackSlotSize = TR::Compiler->om.sizeofReferenceAddress();89int32_t sizeOfParameterAreaInBytes = methodSymbol->getNumParameterSlots() * stackSlotSize;90int32_t firstMappedParmOffsetInBytes;91int32_t parmOffsetInBytes;92int32_t numParmSlots;9394// Compute:95//96// 1) The offset of the first reference parameter, and97// 2) The total range of slots between the first parameter that contains a98// collected reference and the last slot that contains a collected99// reference.100//101// Both quantities must be positive values or 0.102//103if (comp->getOption(TR_MimicInterpreterFrameShape))104{105firstMappedParmOffsetInBytes = 0;106numParmSlots = methodSymbol->getNumParameterSlots();107}108else109{110firstMappedParmOffsetInBytes = sizeOfParameterAreaInBytes;111int32_t lastMappedParmOffsetInBytes = -1;112113for (parmCursor = parameterIterator.getFirst(); parmCursor; parmCursor = parameterIterator.getNext())114{115if ((parmCursor->isReferencedParameter() || comp->getOption(TR_FullSpeedDebug)) && parmCursor->isCollectedReference())116{117parmOffsetInBytes = parmCursor->getParameterOffset();118119if (!_bodyLinkage->getRightToLeft())120{121parmOffsetInBytes = sizeOfParameterAreaInBytes - parmOffsetInBytes - stackSlotSize;122}123124if (parmOffsetInBytes < firstMappedParmOffsetInBytes)125{126firstMappedParmOffsetInBytes = parmOffsetInBytes;127}128129if (parmOffsetInBytes > lastMappedParmOffsetInBytes)130{131lastMappedParmOffsetInBytes = parmOffsetInBytes;132}133}134}135136if (lastMappedParmOffsetInBytes >= firstMappedParmOffsetInBytes)137{138// The range of stack slots between the first and last parameter that139// contain a collected references.140//141numParmSlots = ((lastMappedParmOffsetInBytes-firstMappedParmOffsetInBytes)/stackSlotSize) + 1;142}143else144{145// No collected reference parameters.146//147numParmSlots = 0;148}149}150151TR_ASSERT(firstMappedParmOffsetInBytes >= 0, "firstMappedParmOffsetInBytes must be positive or 0");152TR_ASSERT(numParmSlots >= 0, "numParmSlots must be positive or 0");153154// --------------------------------------------------------------------------------155// Construct the parameter map for mapped reference parameters156//157TR_GCStackMap *parameterMap = new (self()->trHeapMemory(), numParmSlots) TR_GCStackMap(numParmSlots);158159// --------------------------------------------------------------------------------160// Now assign GC map indices to parameters depending on the linkage mapping.161// At the same time populate the parameter map.162//163164// slotIndex is the zero-based index into the GC map bit vector for a reference165// parameter or auto.166//167int32_t slotIndex = 0;168169parameterIterator.reset();170for (parmCursor = parameterIterator.getFirst(); parmCursor; parmCursor = parameterIterator.getNext())171{172if (comp->getOption(TR_MimicInterpreterFrameShape) || comp->getOption(TR_FullSpeedDebug))173{174parmCursor->setParmHasToBeOnStack();175}176177if ((parmCursor->isReferencedParameter() || comp->getOption(TR_MimicInterpreterFrameShape) || comp->getOption(TR_FullSpeedDebug)) &&178parmCursor->isCollectedReference())179{180parmOffsetInBytes = parmCursor->getParameterOffset();181if (!_bodyLinkage->getRightToLeft())182{183parmOffsetInBytes = sizeOfParameterAreaInBytes - parmOffsetInBytes - stackSlotSize;184}185186// Normalize the parameter offset on the stack to a zero-based index187// into the GC map.188//189slotIndex = (parmOffsetInBytes-firstMappedParmOffsetInBytes)/stackSlotSize;190parmCursor->setGCMapIndex(slotIndex);191192if (parmCursor->getLinkageRegisterIndex()<0 ||193parmCursor->getAssignedGlobalRegisterIndex()<0 ||194_bodyLinkage->hasToBeOnStack(parmCursor))195{196parameterMap->setBit(slotIndex);197}198}199}200201// At this point, slotIndex will cover either all the parameter slots or just202// the range of parameters that contain collected references.203//204slotIndex = numParmSlots;205206// --------------------------------------------------------------------------------207// Now assign a GC map index to reference locals. When the stack is mapped,208// these locals will have to be mapped contiguously in the stack according to209// this index.210//211// Locals that need initialization during the method prologue are mapped first,212// then the ones that do not need initialization.213//214215ListIterator<TR::AutomaticSymbol> automaticIterator(&methodSymbol->getAutomaticList());216TR::AutomaticSymbol * localCursor;217218int32_t numberOfPendingPushSlots = 0;219if (comp->getOption(TR_MimicInterpreterFrameShape))220{221for (localCursor = automaticIterator.getFirst(); localCursor; localCursor = automaticIterator.getNext())222{223int32_t assignedIndex = localCursor->getGCMapIndex();224if (assignedIndex >= 0)225{226int32_t nextIndex = assignedIndex + TR::Symbol::convertTypeToNumberOfSlots(localCursor->getDataType());227if (nextIndex > slotIndex)228slotIndex = nextIndex;229}230}231232// There can be holes at the end of auto list, where the auto was declared233// and was never used234//235if (slotIndex < methodSymbol->getFirstJitTempIndex())236{237slotIndex = methodSymbol->getFirstJitTempIndex();238}239240numberOfPendingPushSlots = slotIndex - methodSymbol->getFirstJitTempIndex();241TR_ASSERT(numberOfPendingPushSlots >= 0, "assertion failure");242243for (localCursor = automaticIterator.getFirst(); localCursor; localCursor = automaticIterator.getNext())244{245int32_t assignedIndex = localCursor->getGCMapIndex();246if (assignedIndex >= 0)247{248// FSD requires the JIT to mimic the interpreter stack.249// i.e. for doubles, interpreter expects 2 full slots, even on 64bit platforms.250// Hence, the JIT must calculate the number of slots required by interpreter and251// not the number of address-sized slots required to store the data type.252//253// Note: convertTypeToNumberOfSlots does not handle aggregate types,254// but is safe in this scenario because:255// 1. Symbols of aggregate types have negative GC map indices.256// 2. FSD runs at no-opt => no escape analysis => no aggregates.257//258localCursor->setGCMapIndex(slotIndex -259assignedIndex -260TR::Symbol::convertTypeToNumberOfSlots(localCursor->getDataType()) +261numParmSlots262);263if (debug("traceFSDStackMap"))264{265diagnostic("FSDStackMap: Auto moved from index %d to %d\n", assignedIndex, localCursor->getGCMapIndex());266}267}268}269}270271// Iniialize colour mapping for locals compaction272//273int32_t *colourToGCIndexMap = 0;274275if (doLocalsCompaction)276{277colourToGCIndexMap = (int32_t *) self()->trMemory()->allocateStackMemory(self()->getLocalsIG()->getNumberOfColoursUsedToColour() * sizeof(int32_t));278TR_ASSERT(colourToGCIndexMap, "Failed to allocate colourToGCIndexMap on stack");279280for (int32_t i=0; i<self()->getLocalsIG()->getNumberOfColoursUsedToColour(); ++i)281{282colourToGCIndexMap[i] = -1;283}284}285286// --------------------------------------------------------------------------------287// Map uninitialized reference locals that are not stack allocated objects288//289for (localCursor = automaticIterator.getFirst(); localCursor; localCursor = automaticIterator.getNext())290{291if (localCursor->getGCMapIndex() < 0 &&292localCursor->isCollectedReference() &&293!localCursor->isLocalObject() &&294!localCursor->isInitializedReference() &&295!localCursor->isInternalPointer() &&296!localCursor->isPinningArrayPointer())297{298if (doLocalsCompaction && !localCursor->holdsMonitoredObject())299{300// For reference locals that share a stack slot, make sure they get301// the same GC index.302//303TR_IGNode * igNode;304if ((igNode = self()->getLocalsIG()->getIGNodeForEntity(localCursor)) != NULL)305{306IGNodeColour colour = igNode->getColour();307308if (colourToGCIndexMap[colour] == -1)309{310colourToGCIndexMap[colour] = slotIndex;311}312else313{314localCursor->setGCMapIndex(colourToGCIndexMap[colour]);315if (debug("traceCL"))316{317diagnostic("Shared GC index %d, ref local=%p, %s\n",318localCursor->getGCMapIndex(), localCursor, comp->signature());319}320321continue;322}323}324}325326localCursor->setGCMapIndex(slotIndex);327slotIndex += localCursor->getNumberOfSlots();328}329}330331int32_t numberOfSlotsToBeInitialized = slotIndex - numParmSlots;332333// --------------------------------------------------------------------------------334// Map initialized reference locals and stack allocated objects335//336int32_t numLocalObjectPaddingSlots = 0;337bool localObjectsFound = false;338339for (localCursor = automaticIterator.getFirst(); localCursor; localCursor = automaticIterator.getNext())340{341if (localCursor->getGCMapIndex() < 0 &&342localCursor->isCollectedReference() &&343(localCursor->isLocalObject() || localCursor->isInitializedReference()) &&344!localCursor->isInternalPointer() &&345!localCursor->isPinningArrayPointer())346{347if (doLocalsCompaction &&348!localCursor->holdsMonitoredObject())349{350// For reference locals that share a stack slot, make sure they get351// the same GC index.352//353TR_IGNode * igNode;354if ((igNode = self()->getLocalsIG()->getIGNodeForEntity(localCursor)) != NULL)355{356IGNodeColour colour = igNode->getColour();357358if (colourToGCIndexMap[colour] == -1)359{360colourToGCIndexMap[colour] = slotIndex;361}362else363{364localCursor->setGCMapIndex(colourToGCIndexMap[colour]);365366if (debug("traceCL"))367{368diagnostic("Shared GC index %d, ref local=%p, %s\n",369localCursor->getGCMapIndex(), localCursor, comp->signature());370}371372continue;373}374}375}376377if (localCursor->isLocalObject())378{379localObjectsFound = true;380int32_t localObjectAlignment = comp->fej9()->getLocalObjectAlignmentInBytes();381if (localObjectAlignment > stackSlotSize &&382self()->supportsStackAllocations())383{384// We only get here in compressedrefs mode385int32_t gcMapIndexAlignment = localObjectAlignment / stackSlotSize;386int32_t remainder = (slotIndex - numParmSlots) % gcMapIndexAlignment;387if (remainder)388{389slotIndex += gcMapIndexAlignment - remainder;390numLocalObjectPaddingSlots += gcMapIndexAlignment - remainder;391traceMsg(comp, "GC index of local object %p is adjusted by +%d, and is %d now\n",localCursor, gcMapIndexAlignment - remainder, slotIndex);392}393}394}395396localCursor->setGCMapIndex(slotIndex);397slotIndex += localCursor->getNumberOfSlots();398}399}400401int32_t totalSlotsInMap = slotIndex;402403// --------------------------------------------------------------------------------404// Construct and populate the stack map for a method. Start with all parameters405// and locals being live, and selectively unmark slots that are not live.406//407TR_GCStackMap * localMap = new (self()->trHeapMemory(), totalSlotsInMap) TR_GCStackMap(totalSlotsInMap);408localMap->copy(parameterMap);409410// Set all the local references to be live411//412int32_t i;413for (i = numParmSlots; i < totalSlotsInMap; ++i)414{415localMap->setBit(i);416}417418// Reset the bits for non-reference objects419//420if (comp->getOption(TR_MimicInterpreterFrameShape))421{422for (localCursor = automaticIterator.getFirst(); localCursor; localCursor = automaticIterator.getNext())423{424if (localCursor->getGCMapIndex() >= 0 &&425(!localCursor->isCollectedReference() ||426localCursor->isInternalPointer() ||427localCursor->isPinningArrayPointer()))428{429localMap->resetBit(localCursor->getGCMapIndex());430if (localCursor->getSize() > stackSlotSize)431{432localMap->resetBit(localCursor->getGCMapIndex() + 1);433}434}435}436}437438// --------------------------------------------------------------------------439// Construct and populate the local object stack map440//441// Reset the bits for parts of local objects that are not collected slots442//443TR_GCStackAllocMap *localObjectStackMap = NULL;444445if (localObjectsFound)446{447for (localCursor = automaticIterator.getFirst(); localCursor; localCursor = automaticIterator.getNext())448{449if (localCursor->isCollectedReference() && localCursor->isLocalObject())450{451TR::AutomaticSymbol * localObject = localCursor->getLocalObjectSymbol();452slotIndex = localObject->getGCMapIndex();453454if (!localObjectStackMap)455{456localObjectStackMap = new (self()->trHeapMemory(), totalSlotsInMap) TR_GCStackAllocMap(totalSlotsInMap);457}458459localObjectStackMap->setBit(slotIndex);460461int32_t * collectedSlots = localObject->getReferenceSlots();462int32_t i = 0;463464while (*collectedSlots > 0)465{466int32_t collectedSlotIndex = *collectedSlots;467468// collectedSlotIndex is measured in terms of object field sizes,469// and we want GC map slot sizes, which are not necessarily the same470// (ie. compressed refs)471//472collectedSlotIndex = collectedSlotIndex * TR::Compiler->om.sizeofReferenceField() / stackSlotSize;473for ( ; i < collectedSlotIndex; ++i)474{475localMap->resetBit(slotIndex+i);476}477478localMap->resetBit(slotIndex+i);479i = collectedSlotIndex+1;480collectedSlots++;481}482483for ( ; i < localObject->getSize()/stackSlotSize; ++i)484{485localMap->resetBit(slotIndex+i);486}487}488}489}490491self()->setMethodStackMap(localMap);492493// --------------------------------------------------------------------------494// Now create the stack atlas495//496TR::GCStackAtlas * atlas = new (self()->trHeapMemory()) TR::GCStackAtlas(numParmSlots, totalSlotsInMap, self()->trMemory());497atlas->setParmBaseOffset(firstMappedParmOffsetInBytes);498atlas->setParameterMap(parameterMap);499atlas->setLocalMap(localMap);500atlas->setStackAllocMap(localObjectStackMap);501atlas->setNumberOfSlotsToBeInitialized(numberOfSlotsToBeInitialized);502atlas->setIndexOfFirstSpillTemp(totalSlotsInMap);503atlas->setInternalPointerMap(0);504atlas->setNumberOfPendingPushSlots(numberOfPendingPushSlots);505atlas->setNumberOfPaddingSlots(numLocalObjectPaddingSlots);506self()->setStackAtlas(atlas);507508if (comp->getOption(TR_TraceCG))509{510traceMsg(comp, "totalSlotsInMap is %d, numLocalObjectPaddingSlots is %d\n", totalSlotsInMap, numLocalObjectPaddingSlots);511}512}513514515