Path: blob/master/runtime/compiler/compile/J9Compilation.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2000, 2022 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#pragma csect(CODE,"TRJ9CompBase#C")24#pragma csect(STATIC,"TRJ9CompBase#S")25#pragma csect(TEST,"TRJ9CompBase#T")26#endif2728#include "compile/J9Compilation.hpp"2930#include <stdint.h>31#include "codegen/CodeGenerator.hpp"32#include "codegen/Instruction.hpp"33#include "compile/Compilation.hpp"34#include "compile/Compilation_inlines.hpp"35#include "compile/CompilationTypes.hpp"36#include "compile/ResolvedMethod.hpp"37#include "control/OptimizationPlan.hpp"38#include "control/Options.hpp"39#include "control/Options_inlines.hpp"40#include "control/Recompilation.hpp"41#include "control/RecompilationInfo.hpp"42#include "env/j9method.h"43#include "env/TRMemory.hpp"44#include "env/VMJ9.h"45#include "env/VMAccessCriticalSection.hpp"46#include "env/KnownObjectTable.hpp"47#include "env/VerboseLog.hpp"48#include "il/Node.hpp"49#include "il/Node_inlines.hpp"50#include "ilgen/IlGenRequest.hpp"51#include "infra/List.hpp"52#include "optimizer/Inliner.hpp"53#include "optimizer/OptimizationManager.hpp"54#include "optimizer/Optimizer.hpp"55#include "optimizer/TransformUtil.hpp"56#include "runtime/RuntimeAssumptions.hpp"57#include "runtime/J9Profiler.hpp"58#include "OMR/Bytes.hpp"59#include "il/ParameterSymbol.hpp"60#include "j9.h"61#include "j9cfg.h"626364/*65* There should be no allocations that use the global operator new, since66* all allocations should go through the JitMemory allocation routines.67* To catch cases that we miss, we define global operator new and delete here.68* (xlC won't link statically with the -noe flag when we override these.)69*/70bool firstCompileStarted = false;7172// JITSERVER_TODO: disabled to allow for JITServer73#if !defined(J9VM_OPT_JITSERVER)74void *operator new(size_t size)75{76#if defined(DEBUG)77#if LINUX78// glibc allocates something at dl_init; check if a method is being compiled to avoid79// getting assumes at _dl_init80if (firstCompileStarted)81#endif82{83printf( "\n*** ERROR *** Invalid use of global operator new\n");84TR_ASSERT(0,"Invalid use of global operator new");85}86#endif87return malloc(size);88}8990// Avoid -Wimplicit-exception-spec-mismatch error on platforms that specify the global delete operator with throw()91#ifndef _NOEXCEPT92#define _NOEXCEPT93#endif9495/**96* Since we are using arena allocation, heap deletions must be a no-op, and97* can't be used by JIT code, so we inject an assertion here.98*/99void operator delete(void *) _NOEXCEPT100{101TR_ASSERT(0, "Invalid use of global operator delete");102}103#endif /* !defined(J9VM_OPT_JITSERVER) */104105106107108uint64_t J9::Compilation::_maxYieldIntervalS = 0;109110TR_CallingContext J9::Compilation::_sourceContextForMaxYieldIntervalS = NO_CONTEXT;111112TR_CallingContext J9::Compilation::_destinationContextForMaxYieldIntervalS = NO_CONTEXT;113114TR_Stats** J9::Compilation::_compYieldStatsMatrix = NULL;115116117const char * callingContextNames[] = {118"FBVA_INITIALIZE_CONTEXT",119"FBVA_ANALYZE_CONTEXT",120"BBVA_INITIALIZE_CONTEXT",121"BBVA_ANALYZE_CONTEXT",122"GRA_ASSIGN_CONTEXT",123"PRE_ANALYZE_CONTEXT",124"AFTER_INSTRUCTION_SELECTION_CONTEXT",125"AFTER_REGISTER_ASSIGNMENT_CONTEXT",126"AFTER_POST_RA_SCHEDULING_CONTEXT",127"BEFORE_PROCESS_STRUCTURE_CONTEXT",128"GRA_FIND_LOOPS_AND_CORRESPONDING_AUTOS_BLOCK_CONTEXT",129"GRA_AFTER_FIND_LOOP_AUTO_CONTEXT",130"ESC_CHECK_DEFSUSES_CONTEXT",131"LAST_CONTEXT"132};133134#if defined(J9VM_OPT_JITSERVER)135bool J9::Compilation::_outOfProcessCompilation = false;136#endif /* defined(J9VM_OPT_JITSERVER) */137138J9::Compilation::Compilation(int32_t id,139J9VMThread *j9vmThread,140TR_FrontEnd *fe,141TR_ResolvedMethod *compilee,142TR::IlGenRequest &ilGenRequest,143TR::Options &options,144TR::Region &heapMemoryRegion,145TR_Memory *m,146TR_OptimizationPlan *optimizationPlan,147TR_RelocationRuntime *reloRuntime,148TR::Environment *target)149: OMR::CompilationConnector(150id,151j9vmThread->omrVMThread,152(firstCompileStarted = true, fe),153compilee,154ilGenRequest,155options,156heapMemoryRegion,157m,158optimizationPlan,159target),160_updateCompYieldStats(161options.getOption(TR_EnableCompYieldStats) ||162options.getVerboseOption(TR_VerboseCompYieldStats) ||163TR::Options::_compYieldStatsHeartbeatPeriod > 0),164_maxYieldInterval(0),165_previousCallingContext(NO_CONTEXT),166_sourceContextForMaxYieldInterval(NO_CONTEXT),167_destinationContextForMaxYieldInterval(NO_CONTEXT),168_needsClassLookahead(true),169_reservedDataCache(NULL),170_totalNeededDataCacheSpace(0),171_aotMethodDataStart(NULL),172_curMethodMetadata(NULL),173_getImplInlineable(false),174_vpInfoManager(NULL),175_bpInfoManager(NULL),176_methodBranchInfoList(getTypedAllocator<TR_MethodBranchProfileInfo*>(self()->allocator())),177_externalVPInfoList(getTypedAllocator<TR_ExternalValueProfileInfo*>(self()->allocator())),178_doneHWProfile(false),179_hwpInstructions(m),180_hwpBCMap(m),181_sideEffectGuardPatchSites(getTypedAllocator<TR_VirtualGuardSite*>(self()->allocator())),182_j9VMThread(j9vmThread),183_monitorAutos(m),184_monitorAutoSymRefsInCompiledMethod(getTypedAllocator<TR::SymbolReference*>(self()->allocator())),185_classForOSRRedefinition(m),186_classForStaticFinalFieldModification(m),187_profileInfo(NULL),188_skippedJProfilingBlock(false),189_reloRuntime(reloRuntime),190#if defined(J9VM_OPT_JITSERVER)191_remoteCompilation(false),192_serializedRuntimeAssumptions(getTypedAllocator<SerializedRuntimeAssumption *>(self()->allocator())),193_clientData(NULL),194_stream(NULL),195_globalMemory(*::trPersistentMemory, heapMemoryRegion),196_perClientMemory(_trMemory),197_methodsRequiringTrampolines(getTypedAllocator<TR_OpaqueMethodBlock *>(self()->allocator())),198_deserializedAOTMethod(false),199_deserializedAOTMethodUsingSVM(false),200_aotCacheStore(false),201_serializationRecords(decltype(_serializationRecords)::allocator_type(heapMemoryRegion)),202#endif /* defined(J9VM_OPT_JITSERVER) */203_osrProhibitedOverRangeOfTrees(false)204{205_symbolValidationManager = new (self()->region()) TR::SymbolValidationManager(self()->region(), compilee);206207_aotClassClassPointer = NULL;208_aotClassClassPointerInitialized = false;209210_aotGuardPatchSites = new (m->trHeapMemory()) TR::list<TR_AOTGuardSite*>(getTypedAllocator<TR_AOTGuardSite*>(self()->allocator()));211212_aotClassInfo = new (m->trHeapMemory()) TR::list<TR::AOTClassInfo*>(getTypedAllocator<TR::AOTClassInfo*>(self()->allocator()));213214if (_updateCompYieldStats)215_hiresTimeForPreviousCallingContext = TR::Compiler->vm.getHighResClock(self());216217_profileInfo = new (m->trHeapMemory()) TR_AccessedProfileInfo(heapMemoryRegion);218219for (int i = 0; i < CACHED_CLASS_POINTER_COUNT; i++)220_cachedClassPointers[i] = NULL;221222223// Add known object index to parm 0 so that other optmizations can be unlocked.224// It is safe to do so because method and method symbols of a archetype specimen225// are not shared other methods.226//227TR::KnownObjectTable *knot = self()->getOrCreateKnownObjectTable();228TR::IlGeneratorMethodDetails & details = ilGenRequest.details();229if (knot && details.isMethodHandleThunk())230{231J9::MethodHandleThunkDetails & thunkDetails = static_cast<J9::MethodHandleThunkDetails &>(details);232if (thunkDetails.isCustom())233{234TR::KnownObjectTable::Index index = knot->getOrCreateIndexAt(thunkDetails.getHandleRef());235ListIterator<TR::ParameterSymbol> parms(&_methodSymbol->getParameterList());236TR::ParameterSymbol* parm0 = parms.getFirst();237parm0->setKnownObjectIndex(index);238}239}240}241242J9::Compilation::~Compilation()243{244_profileInfo->~TR_AccessedProfileInfo();245}246247TR_J9VMBase *248J9::Compilation::fej9()249{250return (TR_J9VMBase *)self()->fe();251}252253TR_J9VM *254J9::Compilation::fej9vm()255{256return (TR_J9VM *)self()->fe();257}258259void260J9::Compilation::updateCompYieldStatistics(TR_CallingContext callingContext)261{262// get time of this call263//264uint64_t crtTime = TR::Compiler->vm.getHighResClock(self());265266// compute the difference between 2 consecutive calls267//268static uint64_t hiresClockResolution = TR::Compiler->vm.getHighResClockResolution();269uint64_t ticks = crtTime - _hiresTimeForPreviousCallingContext;270uint64_t diffTime;271272if (hiresClockResolution < 1000000)273diffTime = (ticks * 1000000)/hiresClockResolution;274else275diffTime = ticks / (hiresClockResolution/1000000);276277// update stats for the corresponding cell in the matrix278// May lead to problems in the future when we add multiple compilation threads279//280if (self()->getOption(TR_EnableCompYieldStats))281_compYieldStatsMatrix[(int32_t)_previousCallingContext][(int32_t)callingContext].update((double)diffTime);282283if (self()->getOptions()->getVerboseOption(TR_VerboseCompYieldStats))284{285if (diffTime > _maxYieldInterval)286{287_maxYieldInterval = diffTime;288_sourceContextForMaxYieldInterval = _previousCallingContext;289_destinationContextForMaxYieldInterval = callingContext;290}291}292293if (TR::Options::_compYieldStatsHeartbeatPeriod > 0)294{295if (diffTime > _maxYieldIntervalS)296{297_maxYieldIntervalS = diffTime;298_sourceContextForMaxYieldIntervalS = _previousCallingContext;299_destinationContextForMaxYieldIntervalS = callingContext;300}301}302303// prepare for next call304//305_hiresTimeForPreviousCallingContext = crtTime;306_previousCallingContext = callingContext;307}308309310void311J9::Compilation::allocateCompYieldStatsMatrix()312{313// need to use persistent memory314_compYieldStatsMatrix = (TR_Stats**)TR::Compilation::jitPersistentAlloc(sizeof(TR_Stats *)*(int32_t)LAST_CONTEXT);315316for (int32_t i=0; i < (int32_t)LAST_CONTEXT; i++)317{318_compYieldStatsMatrix[i] = (TR_Stats *)TR::Compilation::jitPersistentAlloc(sizeof(TR_Stats)*(int32_t)LAST_CONTEXT);319for (int32_t j=0; j < (int32_t)LAST_CONTEXT; j++)320{321char buffer[128];322sprintf(buffer, "%d-%d", i,j);323_compYieldStatsMatrix[i][j].setName(buffer);324}325}326}327328void329J9::Compilation::printCompYieldStats()330{331TR_VerboseLog::writeLine(332TR_Vlog_PERF,333"Max yield-to-yield time of %u usec for %s -- %s",334static_cast<uint32_t>(_maxYieldInterval),335J9::Compilation::getContextName(_sourceContextForMaxYieldInterval),336J9::Compilation::getContextName(_destinationContextForMaxYieldInterval));337}338339const char *340J9::Compilation::getContextName(TR_CallingContext context)341{342if (context == OMR::endOpts || context == TR_CallingContext::NO_CONTEXT)343return "NO CONTEXT";344else if (context < OMR::numOpts)345return TR::Optimizer::getOptimizationName((OMR::Optimizations)context);346else347return callingContextNames[context-OMR::numOpts];348}349350void351J9::Compilation::printEntryName(int32_t i, int32_t j)352{353fprintf(stderr, "\n%s -", J9::Compilation::getContextName((TR_CallingContext) i));354fprintf(stderr, "- %s\n", J9::Compilation::getContextName((TR_CallingContext) j));355}356357358void359J9::Compilation::printCompYieldStatsMatrix()360{361if (!_compYieldStatsMatrix)362return; // the matrix may not have been allocated (for instance when we give a bad command line option)363364for (int32_t i=0; i < (int32_t)LAST_CONTEXT; i++)365{366for (int32_t j=0; j < (int32_t)LAST_CONTEXT; j++)367{368TR_Stats *stats = &_compYieldStatsMatrix[i][j];369if (stats->samples() > 0 && stats->maxVal() > TR::Options::_compYieldStatsThreshold)370{371TR::Compilation::printEntryName(i, j);372stats->report(stderr);373}374}375}376}377378TR_AOTMethodHeader *379J9::Compilation::getAotMethodHeaderEntry()380{381J9JITDataCacheHeader *aotMethodHeader = (J9JITDataCacheHeader *)self()->getAotMethodDataStart();382TR_AOTMethodHeader *aotMethodHeaderEntry = (TR_AOTMethodHeader *)(aotMethodHeader + 1);383return aotMethodHeaderEntry;384}385386TR::Node *387J9::Compilation::findNullChkInfo(TR::Node *node)388{389TR_ASSERT((node->getOpCodeValue() == TR::checkcastAndNULLCHK), "should call this only for checkcastAndNullChk\n");390TR::Node * newNode = NULL;391for (auto pair = self()->getCheckcastNullChkInfo().begin(); pair != self()->getCheckcastNullChkInfo().end(); ++pair)392{393if ((*pair)->getKey()->getByteCodeIndex() == node->getByteCodeIndex() &&394(*pair)->getKey()->getCallerIndex() == node->getInlinedSiteIndex())395{396newNode = (*pair)->getValue();397//dumpOptDetails("found bytecodeinfo for node %p as %x [%p]\n", node, newNode->getByteCodeIndex(), newNode);398break;399}400}401TR_ASSERT(newNode, "checkcastAndNullChk node doesnt have a corresponding null chk bytecodeinfo\n");402return newNode;403}404405406/**407* Sometimes we start the compilation with an optLevel, but later on,408* after we get more information, we decide to change it to something else.409* This method is used to change the optLevel. Note that the optLevel410* is cached in various data structures and it needs to be kept in sync.411*/412void413J9::Compilation::changeOptLevel(TR_Hotness newOptLevel)414{415self()->getOptions()->setOptLevel(newOptLevel);416self()->getOptimizationPlan()->setOptLevel(newOptLevel);417if (self()->getRecompilationInfo())418{419TR_PersistentJittedBodyInfo *bodyInfo = self()->getRecompilationInfo()->getJittedBodyInfo();420if (bodyInfo)421bodyInfo->setHotness(newOptLevel);422}423}424425426bool427J9::Compilation::isConverterMethod(TR::RecognizedMethod rm)428{429switch (rm)430{431case TR::sun_nio_cs_ISO_8859_1_Encoder_encodeISOArray:432case TR::java_lang_StringCoding_implEncodeISOArray:433case TR::java_lang_String_decodeUTF8_UTF16:434case TR::sun_nio_cs_ISO_8859_1_Decoder_decodeISO8859_1:435case TR::sun_nio_cs_US_ASCII_Encoder_encodeASCII:436case TR::sun_nio_cs_US_ASCII_Decoder_decodeASCII:437case TR::sun_nio_cs_ext_SBCS_Encoder_encodeSBCS:438case TR::sun_nio_cs_ext_SBCS_Decoder_decodeSBCS:439case TR::sun_nio_cs_UTF_8_Encoder_encodeUTF_8:440case TR::sun_nio_cs_UTF_8_Decoder_decodeUTF_8:441case TR::sun_nio_cs_UTF_16_Encoder_encodeUTF16Big:442case TR::sun_nio_cs_UTF_16_Encoder_encodeUTF16Little:443return true;444default:445return false;446}447448return false;449}450451452//This implicitly checks if method is recognized converter method.453bool454J9::Compilation::canTransformConverterMethod(TR::RecognizedMethod rm)455{456TR_ASSERT(self()->isConverterMethod(rm), "not a converter method\n");457458if (self()->getOption(TR_DisableConverterReducer))459return false;460461bool aot = self()->compileRelocatableCode();462bool genSIMD = self()->cg()->getSupportsVectorRegisters() && !self()->getOption(TR_DisableSIMDArrayTranslate);463bool genTRxx = !aot && self()->cg()->getSupportsArrayTranslateTRxx();464465switch (rm)466{467case TR::sun_nio_cs_ISO_8859_1_Encoder_encodeISOArray:468case TR::java_lang_StringCoding_implEncodeISOArray:469return genTRxx || self()->cg()->getSupportsArrayTranslateTRTO255() || self()->cg()->getSupportsArrayTranslateTRTO() || genSIMD;470471case TR::sun_nio_cs_ISO_8859_1_Decoder_decodeISO8859_1:472return genTRxx || self()->cg()->getSupportsArrayTranslateTROTNoBreak() || genSIMD;473474case TR::sun_nio_cs_US_ASCII_Encoder_encodeASCII:475case TR::sun_nio_cs_UTF_8_Encoder_encodeUTF_8:476return genTRxx || self()->cg()->getSupportsArrayTranslateTRTO() || genSIMD;477478case TR::sun_nio_cs_US_ASCII_Decoder_decodeASCII:479case TR::sun_nio_cs_UTF_8_Decoder_decodeUTF_8:480return genTRxx || self()->cg()->getSupportsArrayTranslateTROT() || genSIMD;481482case TR::sun_nio_cs_ext_SBCS_Encoder_encodeSBCS:483return genTRxx && self()->cg()->getSupportsTestCharComparisonControl();484485case TR::sun_nio_cs_ext_SBCS_Decoder_decodeSBCS:486return genTRxx;487488// devinmp: I'm not sure whether these could be transformed in AOT, but489// they haven't been so far.490case TR::sun_nio_cs_UTF_16_Encoder_encodeUTF16Little:491return !aot && self()->cg()->getSupportsEncodeUtf16LittleWithSurrogateTest();492493case TR::sun_nio_cs_UTF_16_Encoder_encodeUTF16Big:494return !aot && self()->cg()->getSupportsEncodeUtf16BigWithSurrogateTest();495496default:497return false;498}499}500501502bool503J9::Compilation::useCompressedPointers()504{505//FIXME: probably have to query the GC as well506return (self()->target().is64Bit() && TR::Options::useCompressedPointers());507}508509510bool511J9::Compilation::useAnchors()512{513return (self()->useCompressedPointers());514}515516517bool518J9::Compilation::hasBlockFrequencyInfo()519{520return TR_BlockFrequencyInfo::get(self()) != NULL;521}522523bool524J9::Compilation::isShortRunningMethod(int32_t callerIndex)525{526{527const char *sig = NULL;528if (callerIndex > -1)529{530// this should be more reliable, but needs verification as equivalent531sig = self()->getInlinedResolvedMethod(callerIndex)->signature(self()->trMemory());532}533else534sig = self()->signature();535536if (sig &&537((strncmp("java/lang/String.", sig, 17) == 0) ||538(strncmp("java/util/HashMap.", sig, 18) == 0) ||539(strncmp("java/util/TreeMap.", sig, 18) == 0) ||540(strncmp("java/math/DivisionLong.", sig, 23) == 0) ||541(strncmp("com/ibm/xml/xlxp2/scan/util/XMLString.", sig, 38) == 0) ||542(strncmp("com/ibm/xml/xlxp2/scan/util/SymbolMap.", sig, 38) == 0) ||543(strncmp("java/util/Random.next(I)I",sig,25) == 0) ||544(strncmp("java/util/zip/ZipFile.safeToUseModifiedUTF8", sig, 43) == 0) ||545(strncmp("java/util/HashMap$HashIterator.", sig, 31) == 0) ||546(strncmp("sun/misc/FloatingDecimal.readJavaFormatString", sig, 45) == 0)547)548)549{550return true;551}552}553return false;554}555556bool557J9::Compilation::isRecompilationEnabled()558{559560if (!self()->cg()->getSupportsRecompilation())561{562return false;563}564565if (self()->isDLT())566{567return false;568}569570// Don't do recompilation on JNI virtual thunk methods571//572if (self()->getCurrentMethod()->isJNINative())573return false;574575return self()->allowRecompilation();576}577578bool579J9::Compilation::isJProfilingCompilation()580{581return self()->getRecompilationInfo() ? self()->getRecompilationInfo()->getJittedBodyInfo()->getUsesJProfiling() : false;582}583584// See if it is OK to remove this allocation node to e.g. merge it with others585// or allocate it locally on a stack frame.586// If so, return the allocation size if the size is constant, or zero if the587// size is variable.588// If not, return -1.589//590int32_t591J9::Compilation::canAllocateInlineOnStack(TR::Node* node, TR_OpaqueClassBlock* &classInfo)592{593if (self()->compileRelocatableCode())594return -1;595596if (node->getOpCodeValue() == TR::New)597{598J9Class* clazz = self()->fej9vm()->getClassForAllocationInlining(self(), node->getFirstChild()->getSymbolReference());599600if (clazz == NULL)601return -1;602603// Can not inline the allocation on stack if the class is special604if (TR::Compiler->cls.isClassSpecialForStackAllocation((TR_OpaqueClassBlock *)clazz))605return -1;606}607return self()->canAllocateInline(node, classInfo);608}609610611bool612J9::Compilation::canAllocateInlineClass(TR_OpaqueClassBlock *block)613{614if (block == NULL)615return false;616617return self()->fej9()->canAllocateInlineClass(block);618}619620621// This code was previously in canAllocateInlineOnStack. However, it is required by code gen to622// inline heap allocations. The only difference, for now, is that inlined heap allocations623// are being enabled for AOT, but stack allocations are not (yet).624//625int32_t626J9::Compilation::canAllocateInline(TR::Node* node, TR_OpaqueClassBlock* &classInfo)627{628629// Can't skip the allocation if we are generating JVMPI hooks, since630// JVMPI needs to know about the allocation.631//632if (self()->suppressAllocationInlining() || !self()->fej9vm()->supportAllocationInlining(self(), node))633return -1;634635// Pending inline allocation support on platforms for variable new636//637if (node->getOpCodeValue() == TR::variableNew || node->getOpCodeValue() == TR::variableNewArray)638return -1;639640int32_t size;641TR::Node * classRef;642TR::SymbolReference * classSymRef;643TR::StaticSymbol * classSym;644J9Class * clazz;645646bool isRealTimeGC = self()->getOptions()->realTimeGC();647648bool generateArraylets = self()->generateArraylets();649650const bool areValueTypesEnabled = TR::Compiler->om.areValueTypesEnabled();651652if (node->getOpCodeValue() == TR::New)653{654655classRef = node->getFirstChild();656classSymRef = classRef->getSymbolReference();657658classSym = classSymRef->getSymbol()->getStaticSymbol();659660// Check if the class can be inlined allocation.661// The class has to be resolved, initialized, concrete, etc.662clazz = self()->fej9vm()->getClassForAllocationInlining(self(), classSymRef);663if (!self()->canAllocateInlineClass(reinterpret_cast<TR_OpaqueClassBlock*> (clazz)))664return -1;665666classInfo = self()->fej9vm()->getClassOffsetForAllocationInlining(clazz);667668return self()->fej9()->getAllocationSize(classSym, reinterpret_cast<TR_OpaqueClassBlock*> (clazz));669}670671int32_t elementSize;672if (node->getOpCodeValue() == TR::newarray)673{674TR_ASSERT(node->getSecondChild()->getOpCode().isLoadConst(), "Expecting const child \n");675676int32_t arrayClassIndex = node->getSecondChild()->getInt();677clazz = (J9Class *) self()->fej9()->getClassFromNewArrayTypeNonNull(arrayClassIndex);678679if (node->getFirstChild()->getOpCodeValue() != TR::iconst)680{681classInfo = self()->fej9vm()->getPrimitiveArrayAllocationClass(clazz);682return 0;683}684685// Make sure the number constant of elements requested is within reasonable bounds686//687TR_ASSERT(node->getFirstChild()->getOpCode().isLoadConst(), "Expecting const child \n");688size = node->getFirstChild()->getInt();689if (size < 0 || size > 0x000FFFFF)690return -1;691692classInfo = self()->fej9vm()->getPrimitiveArrayAllocationClass(clazz);693694elementSize = TR::Compiler->om.getSizeOfArrayElement(node);695}696else if (node->getOpCodeValue() == TR::anewarray)697{698classRef = node->getSecondChild();699700// In the case of dynamic array allocation, return 0 indicating variable dynamic array allocation,701// unless value types are enabled, in which case return -1 to prevent inline allocation702if (classRef->getOpCodeValue() != TR::loadaddr)703{704classInfo = NULL;705if (areValueTypesEnabled)706{707if (self()->getOption(TR_TraceCG))708{709traceMsg(self(), "cannot inline array allocation @ node %p because value types are enabled\n", node);710}711const char *signature = self()->signature();712713TR::DebugCounter::incStaticDebugCounter(self(), TR::DebugCounter::debugCounterName(self(), "inlineAllocation/dynamicArray/failed/valueTypes/(%s)", signature));714return -1;715}716else717{718return 0;719}720}721722classSymRef = classRef->getSymbolReference();723// Can't skip the allocation if the class is unresolved724//725clazz = self()->fej9vm()->getClassForAllocationInlining(self(), classSymRef);726if (clazz == NULL)727return -1;728729// Arrays of value type classes must have all their elements initialized with the730// default value of the component type. For now, prevent inline allocation of them.731//732if (areValueTypesEnabled && TR::Compiler->cls.isValueTypeClass(reinterpret_cast<TR_OpaqueClassBlock*>(clazz)))733{734return -1;735}736737auto classOffset = self()->fej9()->getArrayClassFromComponentClass(TR::Compiler->cls.convertClassPtrToClassOffset(clazz));738clazz = TR::Compiler->cls.convertClassOffsetToClassPtr(classOffset);739740if (!clazz)741return -1;742743if (node->getFirstChild()->getOpCodeValue() != TR::iconst)744{745classInfo = self()->fej9vm()->getClassOffsetForAllocationInlining(clazz);746return 0;747}748749// Make sure the number of elements requested is in reasonable bounds750//751TR_ASSERT(node->getFirstChild()->getOpCode().isLoadConst(), "Expecting const child \n");752size = node->getFirstChild()->getInt();753if (size < 0 || size > 0x000FFFFF)754return -1;755756classInfo = self()->fej9vm()->getClassOffsetForAllocationInlining(clazz);757758if (self()->useCompressedPointers())759elementSize = TR::Compiler->om.sizeofReferenceField();760else761elementSize = (int32_t)(TR::Compiler->om.sizeofReferenceAddress());762}763764765TR_ASSERT(node->getOpCodeValue() == TR::newarray ||766node->getOpCodeValue() == TR::anewarray, "unexpected allocation node");767768size *= elementSize;769770if (TR::Compiler->om.useHybridArraylets() && TR::Compiler->om.isDiscontiguousArray(size))771{772if (self()->getOption(TR_TraceCG))773traceMsg(self(), "cannot inline array allocation @ node %p because size %d is discontiguous\n", node, size);774return -1;775}776else if (!isRealTimeGC && size == 0)777{778#if (defined(TR_HOST_S390) && defined(TR_TARGET_S390)) || (defined(TR_TARGET_X86) && defined(TR_HOST_X86)) || (defined(TR_TARGET_POWER) && defined(TR_HOST_POWER)) || (defined(TR_TARGET_ARM64) && defined(TR_HOST_ARM64))779size = TR::Compiler->om.discontiguousArrayHeaderSizeInBytes();780if (self()->getOption(TR_TraceCG))781traceMsg(self(), "inline array allocation @ node %p for size 0\n", node);782#else783if (self()->getOption(TR_TraceCG))784traceMsg(self(), "cannot inline array allocation @ node %p because size 0 is discontiguous\n", node);785return -1;786#endif787}788else if (generateArraylets)789{790size += self()->fej9()->getArrayletFirstElementOffset(elementSize, self());791}792else793{794size += TR::Compiler->om.contiguousArrayHeaderSizeInBytes();795}796797if (node->getOpCodeValue() == TR::newarray || self()->useCompressedPointers())798{799size = (int32_t)OMR::align(size, TR::Compiler->om.sizeofReferenceAddress());800}801802if (isRealTimeGC &&803((size < 0) || (size > self()->fej9()->getMaxObjectSizeForSizeClass())))804return -1;805806TR_ASSERT(size != -1, "unexpected array size");807808return size >= J9_GC_MINIMUM_OBJECT_SIZE ? size : J9_GC_MINIMUM_OBJECT_SIZE;809}810811812TR::KnownObjectTable *813J9::Compilation::getOrCreateKnownObjectTable()814{815if (!_knownObjectTable && !self()->getOption(TR_DisableKnownObjectTable))816{817_knownObjectTable = new (self()->trHeapMemory()) TR::KnownObjectTable(self());818}819820return _knownObjectTable;821}822823824void825J9::Compilation::freeKnownObjectTable()826{827if (_knownObjectTable)828{829#if defined(J9VM_OPT_JITSERVER)830if (!isOutOfProcessCompilation())831#endif /* defined(J9VM_OPT_JITSERVER) */832{833TR::VMAccessCriticalSection freeKnownObjectTable(self()->fej9());834835J9VMThread *thread = self()->fej9()->vmThread();836TR_ASSERT(thread, "assertion failure");837838TR_ArrayIterator<uintptr_t> i(&_knownObjectTable->_references);839for (uintptr_t *ref = i.getFirst(); !i.pastEnd(); ref = i.getNext())840thread->javaVM->internalVMFunctions->j9jni_deleteLocalRef((JNIEnv*)thread, (jobject)ref);841}842}843844_knownObjectTable = NULL;845}846847848bool849J9::Compilation::compileRelocatableCode()850{851return self()->fej9()->isAOT_DEPRECATED_DO_NOT_USE();852}853854bool855J9::Compilation::compilePortableCode()856{857return self()->fej9()->inSnapshotMode();858}859860861int32_t862J9::Compilation::maxInternalPointers()863{864if (self()->getOption(TR_DisableInternalPointers))865return 0;866else867return 128;868}869870871void872J9::Compilation::addHWPInstruction(TR::Instruction *instruction,873TR_HWPInstructionInfo::type instructionType,874void *data)875{876if (!self()->getPersistentInfo()->isRuntimeInstrumentationEnabled())877return;878879TR::Node *node = instruction->getNode();880881switch (instructionType)882{883case TR_HWPInstructionInfo::callInstructions:884case TR_HWPInstructionInfo::indirectCallInstructions:885TR_ASSERT(node->getOpCode().isCall(), "Unknown instruction for HW profiling");886break;887case TR_HWPInstructionInfo::returnInstructions:888case TR_HWPInstructionInfo::valueProfileInstructions:889break;890default:891TR_ASSERT(false, "Unknown instruction for HW profiling");892}893894TR_HWPInstructionInfo hwpInstructionInfo = {(void*)instruction,895data,896instructionType};897898_hwpInstructions.add(hwpInstructionInfo);899}900901902void903J9::Compilation::addHWPCallInstruction(TR::Instruction *instruction, bool indirectCall, TR::Instruction *prev)904{905if (indirectCall)906self()->addHWPInstruction(instruction, TR_HWPInstructionInfo::indirectCallInstructions, (void*)prev);907else908self()->addHWPInstruction(instruction, TR_HWPInstructionInfo::callInstructions);909}910911912void913J9::Compilation::addHWPReturnInstruction(TR::Instruction *instruction)914{915self()->addHWPInstruction(instruction, TR_HWPInstructionInfo::returnInstructions);916}917918919void920J9::Compilation::addHWPValueProfileInstruction(TR::Instruction *instruction)921{922self()->addHWPInstruction(instruction, TR_HWPInstructionInfo::valueProfileInstructions);923}924925926void927J9::Compilation::verifyCompressedRefsAnchors()928{929vcount_t visitCount = self()->incVisitCount();930931TR::TreeTop *tt;932for (tt = self()->getStartTree(); tt; tt = tt->getNextTreeTop())933{934TR::Node *node = tt->getNode();935self()->verifyCompressedRefsAnchors(NULL, node, tt, visitCount);936}937}938939void940J9::Compilation::verifyCompressedRefsAnchors(TR::Node *parent, TR::Node *node,941TR::TreeTop *tt, vcount_t visitCount)942{943if (node->getVisitCount() == visitCount)944return;945946node->setVisitCount(visitCount);947948// check stores949//950if (node->getOpCode().isLoadIndirect() ||951(node->getOpCode().isStoreIndirect() &&952!node->getOpCode().isWrtBar()))953{954if (node->getSymbolReference()->getSymbol()->getDataType() == TR::Address &&955node->getOpCode().isRef())956TR_ASSERT(0, "indirect store %p not lowered!\n", node);957}958959// check children for loads/stores960//961for (int32_t i = node->getNumChildren()-1; i >= 0; i--)962{963TR::Node *child = node->getChild(i);964self()->verifyCompressedRefsAnchors(node, child, tt, visitCount);965}966}967968bool969J9::Compilation::verifyCompressedRefsAnchors(bool anchorize)970{971bool status = true;972973vcount_t visitCount = self()->incVisitCount();974TR::list<TR_Pair<TR::Node, TR::TreeTop> *> nodesList(getTypedAllocator<TR_Pair<TR::Node, TR::TreeTop> *>(self()->allocator()));975TR::TreeTop *tt;976for (tt = self()->getStartTree(); tt; tt = tt->getNextTreeTop())977{978TR::Node *n = tt->getNode();979self()->verifyCompressedRefsAnchors(NULL, n, tt, visitCount, nodesList);980}981982// create anchors if required983if (anchorize)984{985TR_Pair<TR::Node, TR::TreeTop> *info;986// all non-null tt fields indicate some loads/stores were found987// with no corresponding anchors988//989for (auto info = nodesList.begin(); info != nodesList.end(); ++info)990{991TR::TreeTop *tt = (*info)->getValue();992if (tt)993{994TR::Node *n = (*info)->getKey();995dumpOptDetails(self(), "No anchor found for load/store [%p]\n", n);996if (TR::TransformUtil::fieldShouldBeCompressed(n, self()))997{998status = false;999dumpOptDetails(self(), "placing anchor at [%p]\n", tt->getNode());1000TR::TreeTop *newTT = TR::TreeTop::create(self(),1001TR::Node::createCompressedRefsAnchor( n),1002NULL, NULL);1003#if 0 ///#ifdef DEBUG1004TR_ASSERT(0, "No anchor found for load/store [%p]", n);1005#else1006// For the child of null check or resolve check, the side effect doesn't rely on the1007// value of the child, thus the anchor needs to be placed after tt. For other nodes,1008// place the anchor before tt.1009//1010TR::TreeTop *next = tt->getNextTreeTop();1011if ((tt->getNode()->getOpCode().isNullCheck()1012|| tt->getNode()->getOpCode().isResolveCheck())1013&& n == tt->getNode()->getFirstChild())1014{1015tt->join(newTT);1016newTT->join(next);1017}1018else1019{1020TR::TreeTop *prev = tt->getPrevTreeTop();1021prev->join(newTT);1022// Previously, the below path only applied to store nodes (hence1023// the isTreeTop() check). However, it's now been made to apply to1024// void-type nodes as well. This is to account for nodes such as1025// TR::arrayset. Specifically, in the case where the child to be set1026// in an arrayset node is an indirect reference (e.g static String),1027// we need to treat the arrayset node as an indirect store (and compress1028// the reference accordingly)1029if (n->getOpCode().isTreeTop() || n->getOpCode().isVoid())1030{1031newTT->join(next);10321033// In the case where the void node's (e.g TR::arrayset) parent is1034// not itself (e.g it's a TR::treetop), we anchor the arrayset node and it's children1035// under a compressedRefs node and remove the original arrayset tree1036// found under TR::treetop. The reference count of the arrayset node is1037// incremented when we create the compressedRefs anchor, but not when1038// we 'remove' the TR::treetop node. Hence we must recursively decrement1039// here.1040if (n != tt->getNode())1041{1042for (int i = 0; i < tt->getNode()->getNumChildren(); i++)1043tt->getNode()->getChild(i)->recursivelyDecReferenceCount();1044}1045}1046else1047newTT->join(tt);1048}1049status = true;1050#endif1051}1052else1053dumpOptDetails(self(), "field at [%p] need not be compressed\n", n);1054}1055else1056dumpOptDetails(self(), "Anchor found for load/store [%p]\n", (*info)->getKey());1057}1058}1059return status;1060}106110621063static TR_Pair<TR::Node, TR::TreeTop> *findCPtrsInfo(TR::list<TR_Pair<TR::Node, TR::TreeTop> *> &haystack,1064TR::Node *needle)1065{1066for (auto info = haystack.begin(); info != haystack.end(); ++info)1067{1068if ((*info)->getKey() == needle)1069return *info;1070}1071return NULL;1072}107310741075void1076J9::Compilation::verifyCompressedRefsAnchors(TR::Node *parent, TR::Node *node,1077TR::TreeTop *tt, vcount_t visitCount,1078TR::list<TR_Pair<TR::Node, TR::TreeTop> *> &nodesList)1079{1080if (node->getVisitCount() == visitCount)1081return;10821083// process loads/stores that are references1084//1085if (((node->getOpCode().isLoadIndirect() || node->getOpCode().isStoreIndirect()) &&1086node->getSymbolReference()->getSymbol()->getDataType() == TR::Address) ||1087(node->getOpCodeValue() == TR::arrayset && node->getSecondChild()->getDataType() == TR::Address))1088{1089TR_Pair<TR::Node, TR::TreeTop> *info = findCPtrsInfo(nodesList, node);10901091// check if the load/store is already under an anchor1092// if so, this load/store will be lowered correctly1093//1094if (parent && parent->getOpCodeValue() == TR::compressedRefs)1095{1096// set tt value to null to indicate success1097//1098if (info)1099info->setValue(NULL);11001101// donot process this node again1102//1103node->setVisitCount(visitCount);1104}1105else1106{1107// either encountered the load/store for the first time in which1108// case record it,1109// -or-1110// its referenced multiple times in which case do nothing until1111// an anchor is found1112//1113if (!info)1114{1115// add node, tt to the nodesList1116TR_Pair<TR::Node, TR::TreeTop> *newVal = new (self()->trStackMemory()) TR_Pair<TR::Node, TR::TreeTop> (node, tt);1117nodesList.push_front(newVal);1118}1119}1120}1121else1122node->setVisitCount(visitCount);11231124// process the children1125//1126for (int32_t i = node->getNumChildren()-1; i >=0; i--)1127{1128TR::Node *child = node->getChild(i);1129self()->verifyCompressedRefsAnchors(node, child, tt, visitCount, nodesList);1130}1131}113211331134TR_VirtualGuardSite *1135J9::Compilation::addSideEffectNOPSite()1136{1137TR_VirtualGuardSite *site = new /* (PERSISTENT_NEW)*/ (self()->trHeapMemory()) TR_VirtualGuardSite;1138_sideEffectGuardPatchSites.push_front(site);1139return site;1140}114111421143TR_AOTGuardSite *1144J9::Compilation::addAOTNOPSite()1145{1146TR_AOTGuardSite *site = new /* (PERSISTENT_NEW)*/ (self()->trHeapMemory()) TR_AOTGuardSite;1147_aotGuardPatchSites->push_front(site);1148return site;1149}11501151bool1152J9::Compilation::incInlineDepth(TR::ResolvedMethodSymbol * method, TR_ByteCodeInfo & bcInfo, int32_t cpIndex, TR::SymbolReference *callSymRef, bool directCall, TR_PrexArgInfo *argInfo)1153{1154TR_ASSERT_FATAL(callSymRef == NULL, "Should not be calling this API for non-NULL symref!\n");1155return OMR::CompilationConnector::incInlineDepth(method, bcInfo, cpIndex, callSymRef, directCall, argInfo);1156}11571158bool1159J9::Compilation::isGeneratedReflectionMethod(TR_ResolvedMethod * method)1160{11611162if (!method) return false;11631164if (strstr(method->signature(self()->trMemory()), "sun/reflect/GeneratedMethodAccessor"))1165return true;11661167return false;1168}11691170TR_ExternalRelocationTargetKind1171J9::Compilation::getReloTypeForMethodToBeInlined(TR_VirtualGuardSelection *guard, TR::Node *callNode, TR_OpaqueClassBlock *receiverClass)1172{1173TR_ExternalRelocationTargetKind reloKind = OMR::Compilation::getReloTypeForMethodToBeInlined(guard, callNode, receiverClass);11741175if (callNode && self()->compileRelocatableCode())1176{1177if (guard && guard->_kind == TR_ProfiledGuard)1178{1179if (guard->_type == TR_MethodTest)1180reloKind = TR_ProfiledMethodGuardRelocation;1181else if (guard->_type == TR_VftTest)1182reloKind = TR_ProfiledClassGuardRelocation;1183}1184else1185{1186TR::MethodSymbol *methodSymbol = callNode->getSymbolReference()->getSymbol()->castToMethodSymbol();11871188if (methodSymbol->isSpecial())1189{1190reloKind = TR_InlinedSpecialMethod;1191}1192else if (methodSymbol->isStatic())1193{1194reloKind = TR_InlinedStaticMethod;1195}1196else if (receiverClass1197&& TR::Compiler->cls.isAbstractClass(self(), receiverClass)1198&& methodSymbol->getResolvedMethodSymbol()->getResolvedMethod()->isAbstract())1199{1200reloKind = TR_InlinedAbstractMethod;1201}1202else if (methodSymbol->isVirtual())1203{1204reloKind = TR_InlinedVirtualMethod;1205}1206else if (methodSymbol->isInterface())1207{1208reloKind = TR_InlinedInterfaceMethod;1209}1210}12111212if (reloKind == TR_NoRelocation)1213{1214TR_InlinedCallSite *site = self()->getCurrentInlinedCallSite();1215TR_OpaqueMethodBlock *caller;1216if (site)1217{1218caller = site->_methodInfo;1219}1220else1221{1222caller = self()->getMethodBeingCompiled()->getNonPersistentIdentifier();1223}12241225TR_ASSERT_FATAL(false, "Can't find relo kind for Caller %p Callee %p TR_ByteCodeInfo %p\n",1226caller,1227callNode->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod()->getNonPersistentIdentifier(),1228callNode->getByteCodeInfo());1229}1230}12311232return reloKind;1233}12341235bool1236J9::Compilation::compilationShouldBeInterrupted(TR_CallingContext callingContext)1237{1238return self()->fej9()->compilationShouldBeInterrupted(self(), callingContext);1239}12401241void1242J9::Compilation::enterHeuristicRegion()1243{1244if (self()->getOption(TR_UseSymbolValidationManager)1245&& self()->compileRelocatableCode())1246{1247self()->getSymbolValidationManager()->enterHeuristicRegion();1248}1249}12501251void1252J9::Compilation::exitHeuristicRegion()1253{1254if (self()->getOption(TR_UseSymbolValidationManager)1255&& self()->compileRelocatableCode())1256{1257self()->getSymbolValidationManager()->exitHeuristicRegion();1258}1259}12601261bool1262J9::Compilation::validateTargetToBeInlined(TR_ResolvedMethod *implementer)1263{1264if (self()->getOption(TR_UseSymbolValidationManager)1265&& self()->compileRelocatableCode())1266{1267return self()->getSymbolValidationManager()->addMethodFromClassRecord(implementer->getPersistentIdentifier(),1268implementer->classOfMethod(),1269-1);1270}1271return true;1272}127312741275void1276J9::Compilation::reportILGeneratorPhase()1277{1278self()->fej9()->reportILGeneratorPhase();1279}128012811282void1283J9::Compilation::reportAnalysisPhase(uint8_t id)1284{1285self()->fej9()->reportAnalysisPhase(id);1286}128712881289void1290J9::Compilation::reportOptimizationPhase(OMR::Optimizations opts)1291{1292self()->fej9()->reportOptimizationPhase(opts);1293}129412951296void1297J9::Compilation::reportOptimizationPhaseForSnap(OMR::Optimizations opts)1298{1299self()->fej9()->reportOptimizationPhaseForSnap(opts, self());1300}130113021303TR::Compilation::CompilationPhase1304J9::Compilation::saveCompilationPhase()1305{1306return self()->fej9()->saveCompilationPhase();1307}130813091310void1311J9::Compilation::restoreCompilationPhase(TR::Compilation::CompilationPhase phase)1312{1313self()->fej9()->restoreCompilationPhase(phase);1314}13151316void1317J9::Compilation::addMonitorAuto(TR::RegisterMappedSymbol * a, int32_t callerIndex)1318{1319TR_Array<List<TR::RegisterMappedSymbol> *> & monitorAutos = self()->getMonitorAutos();1320List<TR::RegisterMappedSymbol> * autos = monitorAutos[callerIndex + 1];1321if (!autos)1322monitorAutos[callerIndex + 1] = autos = new (self()->trHeapMemory()) List<TR::RegisterMappedSymbol>(self()->trMemory());13231324autos->add(a);1325}13261327void1328J9::Compilation::addAsMonitorAuto(TR::SymbolReference* symRef, bool dontAddIfDLT)1329{1330symRef->getSymbol()->setHoldsMonitoredObject();1331int32_t siteIndex = self()->getCurrentInlinedSiteIndex();1332if (!self()->isPeekingMethod())1333{1334self()->addMonitorAuto(symRef->getSymbol()->castToRegisterMappedSymbol(), siteIndex);1335if (!dontAddIfDLT)1336{1337if (siteIndex == -1)1338self()->getMonitorAutoSymRefsInCompiledMethod()->push_front(symRef);1339}1340else1341{1342// only add the symref into the list for initialization when not in DLT and not peeking.1343// in DLT, we already use the corresponding slot to store the locked object from the interpreter1344// so initializing the symRef later in the block can overwrite the first store.1345if (!self()->isDLT() && siteIndex == -1)1346self()->getMonitorAutoSymRefsInCompiledMethod()->push_front(symRef);1347}1348}1349}13501351TR_OpaqueClassBlock *1352J9::Compilation::getClassClassPointer(bool isVettedForAOT)1353{1354if (!isVettedForAOT || self()->getOption(TR_UseSymbolValidationManager))1355{1356TR_OpaqueClassBlock *jlObject = self()->getObjectClassPointer();1357return jlObject ? self()->fe()->getClassClassPointer(jlObject) : 0;1358}13591360if (_aotClassClassPointerInitialized)1361return _aotClassClassPointer;13621363_aotClassClassPointerInitialized = true;13641365bool jlObjectVettedForAOT = true;1366TR_OpaqueClassBlock *jlObject = self()->fej9()->getClassFromSignature(1367"Ljava/lang/Object;",136818,1369self()->getCurrentMethod(),1370jlObjectVettedForAOT);13711372if (jlObject == NULL)1373return NULL;13741375TR_OpaqueClassBlock *jlClass = self()->fe()->getClassClassPointer(jlObject);1376if (jlClass == NULL)1377return NULL;13781379TR_ResolvedJ9Method *method = (TR_ResolvedJ9Method*)self()->getCurrentMethod();1380if (!method->validateArbitraryClass(self(), (J9Class*)jlClass))1381return NULL;13821383_aotClassClassPointer = jlClass;1384return jlClass;1385}13861387TR_OpaqueClassBlock *1388J9::Compilation::getObjectClassPointer()1389{1390return self()->getCachedClassPointer(OBJECT_CLASS_POINTER);1391}13921393TR_OpaqueClassBlock *1394J9::Compilation::getRunnableClassPointer()1395{1396return self()->getCachedClassPointer(RUNNABLE_CLASS_POINTER);1397}13981399TR_OpaqueClassBlock *1400J9::Compilation::getStringClassPointer()1401{1402return self()->getCachedClassPointer(STRING_CLASS_POINTER);1403}14041405TR_OpaqueClassBlock *1406J9::Compilation::getSystemClassPointer()1407{1408return self()->getCachedClassPointer(SYSTEM_CLASS_POINTER);1409}14101411TR_OpaqueClassBlock *1412J9::Compilation::getReferenceClassPointer()1413{1414return self()->getCachedClassPointer(REFERENCE_CLASS_POINTER);1415}14161417TR_OpaqueClassBlock *1418J9::Compilation::getJITHelpersClassPointer()1419{1420return self()->getCachedClassPointer(JITHELPERS_CLASS_POINTER);1421}14221423TR_OpaqueClassBlock *1424J9::Compilation::getCachedClassPointer(CachedClassPointerId which)1425{1426TR_OpaqueClassBlock *clazz = _cachedClassPointers[which];1427if (clazz != NULL)1428return clazz;14291430if (self()->compileRelocatableCode()1431&& !self()->getOption(TR_UseSymbolValidationManager))1432return NULL;14331434static const char * const names[] =1435{1436"Ljava/lang/Object;",1437"Ljava/lang/Runnable;",1438"Ljava/lang/String;",1439"Ljava/lang/System;",1440"Ljava/lang/ref/Reference;",1441"Lcom/ibm/jit/JITHelpers;",1442};14431444static_assert(1445sizeof (names) / sizeof (names[0]) == CACHED_CLASS_POINTER_COUNT,1446"wrong number of entries in J9::Compilation cached class names array");14471448const char *name = names[which];1449clazz = self()->fej9()->getClassFromSignature(1450name,1451strlen(name),1452self()->getCurrentMethod());14531454_cachedClassPointers[which] = clazz;1455return clazz;1456}14571458/*1459* Adds the provided TR_OpaqueClassBlock to the set of those to trigger OSR Guard patching1460* on a redefinition.1461* Cheaper implementation would be a set, not an array.1462*/1463void1464J9::Compilation::addClassForOSRRedefinition(TR_OpaqueClassBlock *clazz)1465{1466for (uint32_t i = 0; i < _classForOSRRedefinition.size(); ++i)1467if (_classForOSRRedefinition[i] == clazz)1468return;14691470_classForOSRRedefinition.add(clazz);1471}14721473/*1474* Adds the provided TR_OpaqueClassBlock to the set of those to trigger OSR Guard patching1475* on a static final field modification.1476*/1477void1478J9::Compilation::addClassForStaticFinalFieldModification(TR_OpaqueClassBlock *clazz)1479{1480// Class redefinition can also modify static final fields1481self()->addClassForOSRRedefinition(clazz);14821483for (uint32_t i = 0; i < _classForStaticFinalFieldModification.size(); ++i)1484if (_classForStaticFinalFieldModification[i] == clazz)1485return;14861487_classForStaticFinalFieldModification.add(clazz);1488}14891490/*1491* Controls if pending push liveness is stashed during IlGen to reduce OSRLiveRange1492* overhead.1493*/1494bool1495J9::Compilation::pendingPushLivenessDuringIlgen()1496{1497static bool enabled = (feGetEnv("TR_DisablePendingPushLivenessDuringIlGen") == NULL);1498if (self()->getOSRMode() == TR::involuntaryOSR)1499return false;1500else return enabled;1501}15021503bool1504J9::Compilation::supportsQuadOptimization()1505{1506if (self()->isDLT() || self()->getOption(TR_FullSpeedDebug))1507return false;1508return true;1509}151015111512bool1513J9::Compilation::notYetRunMeansCold()1514{1515if (self()->getOptimizer() && !(self()->getOptimizer()->isIlGenOpt()))1516return false;15171518TR_ResolvedMethod *currentMethod = self()->getJittedMethodSymbol()->getResolvedMethod();15191520intptr_t initialCount = currentMethod->hasBackwardBranches() ?1521self()->getOptions()->getInitialBCount() :1522self()->getOptions()->getInitialCount();15231524switch (currentMethod->getRecognizedMethod())1525{1526case TR::com_ibm_jit_DecimalFormatHelper_formatAsDouble:1527case TR::com_ibm_jit_DecimalFormatHelper_formatAsFloat:1528initialCount = 0;1529break;1530default:1531break;1532}15331534if (currentMethod->containingClass() == self()->getStringClassPointer())1535{1536if (currentMethod->isConstructor())1537{1538char *sig = currentMethod->signatureChars();1539if (!strncmp(sig, "([CIIII)", 8) ||1540!strncmp(sig, "([CIICII)", 9) ||1541!strncmp(sig, "(II[C)", 6))1542initialCount = 0;1543}1544else1545{1546char *sig = "isRepeatedCharCacheHit";1547if (strncmp(currentMethod->nameChars(), sig, strlen(sig)) == 0)1548initialCount = 0;1549}1550}15511552if (1553self()->isDLT()1554|| (initialCount < TR_UNRESOLVED_IMPLIES_COLD_COUNT)1555|| ((self()->getOption(TR_UnresolvedAreNotColdAtCold) && self()->getMethodHotness() == cold) || self()->getMethodHotness() < cold)1556|| currentMethod->convertToMethod()->isArchetypeSpecimen()1557|| ( self()->getCurrentMethod()1558&& self()->getCurrentMethod()->convertToMethod()->isArchetypeSpecimen())1559)1560return false;1561else1562return true;1563}15641565bool1566J9::Compilation::incompleteOptimizerSupportForReadWriteBarriers()1567{1568return self()->getOption(TR_EnableFieldWatch);1569}15701571#if defined(J9VM_OPT_JITSERVER)1572void1573J9::Compilation::addSerializationRecord(const AOTCacheRecord *record, uintptr_t reloDataOffset)1574{1575TR_ASSERT_FATAL(_aotCacheStore, "Trying to add serialization record for compilation that is not an AOT cache store");1576if (record)1577_serializationRecords.push_back({ record, reloDataOffset });1578else1579_aotCacheStore = false;// Serialization failed; method won't be stored in AOT cache1580}1581#endif /* defined(J9VM_OPT_JITSERVER) */158215831584