Path: blob/master/runtime/compiler/optimizer/InlinerTempForJ9.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*******************************************************************************/21#include <algorithm>22#include "j9cfg.h"23#include "optimizer/Inliner.hpp"24#include "optimizer/J9Inliner.hpp"25#include "optimizer/J9EstimateCodeSize.hpp"26#include "optimizer/VectorAPIExpansion.hpp"2728#include "env/KnownObjectTable.hpp"29#include "compile/InlineBlock.hpp"30#include "compile/Method.hpp"31#include "compile/OSRData.hpp"32#include "compile/ResolvedMethod.hpp"33#include "env/CompilerEnv.hpp"34#include "env/CHTable.hpp"35#include "env/PersistentCHTable.hpp"36#include "env/VMJ9.h"37#include "env/jittypes.h"38#include "il/Block.hpp"39#include "il/Node.hpp"40#include "il/Node_inlines.hpp"41#include "il/ParameterSymbol.hpp"42#include "il/StaticSymbol.hpp"43#include "il/TreeTop.hpp"44#include "il/TreeTop_inlines.hpp"45#include "optimizer/CallInfo.hpp"46#include "optimizer/J9CallGraph.hpp"47#include "optimizer/PreExistence.hpp"48#include "optimizer/Structure.hpp"49#include "codegen/CodeGenerator.hpp"50#include "codegen/CodeGenerator_inlines.hpp"51#include "il/ILOpCodes.hpp"52#include "il/ILOps.hpp"53#include "ilgen/IlGenRequest.hpp"54#include "ilgen/IlGeneratorMethodDetails.hpp"55#include "ilgen/IlGeneratorMethodDetails_inlines.hpp"56#include "optimizer/Structure.hpp" // TR_RegionAnalysis57#include "optimizer/StructuralAnalysis.hpp"58#include "control/Recompilation.hpp" //TR_PersistentJittedBodyInfo59#include "control/RecompilationInfo.hpp" //TR_PersistentJittedBodyInfo60#include "optimizer/EstimateCodeSize.hpp"61#include "env/VMJ9.h"62#include "runtime/J9Profiler.hpp"63#include "ras/DebugCounter.hpp"64#include "j9consts.h"65#include "optimizer/TransformUtil.hpp"6667namespace TR { class SimpleRegex; }6869#define OPT_DETAILS "O^O INLINER: "7071// == Hack markers ==7273// To conserve owning method indexes, we share TR_ResolvedMethods even where74// the owning method differs. Usually that is done only for methods that the75// inliner never sees, but if we get aggressive and share TR_ResolvedMethods76// that are exposed to the inliner, then the inliner needs to make sure it77// doesn't rely on the "owning method" accurately representing the calling method.78//79// This is a fragile design that needs some more thought. We should either80// eliminate the limitations that motivate sharing in the first place, or else81// take the time to modify inliner (and everyone else) so it doesn't rely on82// owning method information to indicate the caller.83//84// For now, we mark such code with this macro.85//86#define OWNING_METHOD_MAY_NOT_BE_THE_CALLER (1)8788#define MIN_NUM_CALLERS 2089#define MIN_FAN_IN_SIZE 5090#define SIZE_MULTIPLIER 491#define FANIN_OTHER_BUCKET_THRESHOLD 0.592#define DEFAULT_CONST_CLASS_WEIGHT 109394#undef TRACE_CSI_IN_INLINER9596const char* TR_PrexArgument::priorKnowledgeStrings[] = { "", "(preexistent) ", "(fixed-class) ", "(known-object) " };9798static bool isWarm(TR::Compilation *comp)99{100return comp->getMethodHotness() >= warm;101}102static bool isHot(TR::Compilation *comp)103{104return comp->getMethodHotness() >= hot;105}106static bool isScorching(TR::Compilation *comp)107{108return ((comp->getMethodHotness() >= scorching) || ((comp->getMethodHotness() >= veryHot) && comp->isProfilingCompilation())) ;109}110111static int32_t getJ9InitialBytecodeSize(TR_ResolvedMethod * feMethod, TR::ResolvedMethodSymbol * methodSymbol, TR::Compilation *comp)112{113int32_t size = feMethod->maxBytecodeIndex();114115if (methodSymbol && methodSymbol->getRecognizedMethod() == TR::java_util_ArrayList_remove)116{117size >>= 1;118}119120if (feMethod->getRecognizedMethod() == TR::java_lang_String_indexOf_String_int ||121feMethod->getRecognizedMethod() == TR::java_lang_String_init_String ||122feMethod->getRecognizedMethod() == TR::java_lang_String_indexOf_fast ||123feMethod->getRecognizedMethod() == TR::java_math_BigDecimal_subMulSetScale ||124feMethod->getRecognizedMethod() == TR::java_math_BigDecimal_addAddMulSetScale ||125feMethod->getRecognizedMethod() == TR::java_math_BigDecimal_mulSetScale ||126feMethod->getRecognizedMethod() == TR::java_math_BigDecimal_noLLOverflowAdd ||127feMethod->getRecognizedMethod() == TR::java_math_BigDecimal_noLLOverflowMul ||128feMethod->getRecognizedMethod() == TR::java_math_BigDecimal_subMulAddAddMulSetScale ||129feMethod->getRecognizedMethod() == TR::com_ibm_ws_webcontainer_channel_WCCByteBufferOutputStream_printUnencoded ||130feMethod->getRecognizedMethod() == TR::java_lang_String_equals)131{132size >>= 1;133}134135else if (feMethod->isDAAWrapperMethod())136{137size = 1;138}139140else if (feMethod->isDAAIntrinsicMethod())141{142size >>= 3;143}144145else if (feMethod->getRecognizedMethod() == TR::java_math_BigDecimal_valueOf )146{147size >>= 2;148}149else if (feMethod->getRecognizedMethod() == TR::java_math_BigDecimal_add ||150feMethod->getRecognizedMethod() == TR::java_lang_String_init_int_String_int_String_String ||151feMethod->getRecognizedMethod() == TR::com_ibm_jit_DecimalFormatHelper_formatAsDouble ||152feMethod->getRecognizedMethod() == TR::com_ibm_jit_DecimalFormatHelper_formatAsFloat)153{154size >>= 3;155}156157else if (strncmp(feMethod->nameChars(), "toString", 8) == 0 ||158strncmp(feMethod->nameChars(), "multiLeafArrayCopy", 18) == 0)159{160size >>= 1;161}162else if (!comp->getOption(TR_DisableAdaptiveDumbInliner))163{164if (methodSymbol && !methodSymbol->mayHaveInlineableCall() && size <= 5) // favor the inlining of methods that are very small165size = 0;166}167168TR_J9EstimateCodeSize::adjustEstimateForStringCompression(feMethod, size, TR_J9EstimateCodeSize::STRING_COMPRESSION_ADJUSTMENT_FACTOR);169170return size;171}172173static bool insideIntPipelineForEach(TR_ResolvedMethod *method, TR::Compilation *comp)174{175char *sig = "accept";176bool returnValue = true; //default is true since if first method is IntPipeline.forEach true is returned177178//Searches up the owning method chain until IntPipeline.forEach is found179//If the first method passed into this function is IntPipeline$Head.forEach or IntPipeline.forEach, true is returned180//since IntPipeline$Head.forEach and IntPipeline.forEach needs to be inlined for JIT GPU.181//If not the method name is checked to see if it is called accept.182//If the method in the chain just before IntPipeline.forEach is accept, true is also returned183//This tries to inline accept and the methods inside accept184//IntPipelineHead.forEach must also be inlined.185if (method && comp->getOptions()->getEnableGPU(TR_EnableGPU) && comp->hasIntStreamForEach())186{187if (method->getRecognizedMethod() == TR::java_util_stream_IntPipelineHead_forEach)188return true;189190while (method)191{192if (method->getRecognizedMethod() == TR::java_util_stream_IntPipeline_forEach)193return returnValue;194195//If the current method is accept, true is returned if the next method is IntPipeline.forEach196//Otherwise, if the next method is IntPipeline.forEach, false is returned197if (strncmp(method->nameChars(), sig, strlen(sig)) == 0)198returnValue = true;199else200returnValue = false;201202method = method->owningMethod();203}204}205206return false;207}208209bool210TR_J9InlinerPolicy::inlineRecognizedMethod(TR::RecognizedMethod method)211{212// if (method ==213// TR::java_lang_String_init_String_char)214// return false;215if (comp()->cg()->suppressInliningOfRecognizedMethod(method))216return false;217218if (comp()->isConverterMethod(method) &&219comp()->canTransformConverterMethod(method))220return false;221222// Check for memoizing methods223if (comp()->getOption(TR_DisableDememoization) || (comp()->getMethodHotness() < hot)) // TODO: This should actually check whether EA will run, but that's not crucial for correctness224{225switch (method)226{227case TR::java_lang_Integer_valueOf:228comp()->getMethodSymbol()->setHasNews(true);229return true;230default:231break;232}233}234else if (method == TR::java_lang_Integer_valueOf)235return false;236237if (willBeInlinedInCodeGen(method))238return false;239240return true;241242}243244int32_t245TR_J9InlinerPolicy::getInitialBytecodeSize(TR_ResolvedMethod *feMethod, TR::ResolvedMethodSymbol * methodSymbol, TR::Compilation *comp)246{247return getJ9InitialBytecodeSize(feMethod, methodSymbol, comp);248}249250bool251TR_J9InlinerPolicy::aggressivelyInlineInLoops()252{253return _aggressivelyInlineInLoops;254}255256void257TR_J9InlinerPolicy::determineAggressionInLoops(TR::ResolvedMethodSymbol *callerSymbol)258{259if (isHot(comp()) && OMR_InlinerPolicy::getInitialBytecodeSize(callerSymbol, comp()) < 100)260_aggressivelyInlineInLoops = true;261}262263void264TR_J9InlinerPolicy::determineInliningHeuristic(TR::ResolvedMethodSymbol *callerSymbol)265{266determineAggressionInLoops(callerSymbol);267return;268}269270void TR_MultipleCallTargetInliner::generateNodeEstimate::operator ()(TR_CallTarget *ct, TR::Compilation *comp)271{272int32_t size = getJ9InitialBytecodeSize(ct->_calleeMethod, 0, comp);273274// only scale the inlining size when the method is non-empty - conversion of275// NaN/Inf to int is undefined and an empty method partially inlined instead276// of fully inlined is still empty277if(ct->_isPartialInliningCandidate && ct->_fullSize != 0)278{279size = size * ((float)(ct->_partialSize)/(float)(ct->_fullSize));280}281_nodeEstimate += size;282}283284bool285TR_J9InlinerPolicy::mustBeInlinedEvenInDebug(TR_ResolvedMethod * calleeMethod, TR::TreeTop *callNodeTreeTop)286{287if (calleeMethod)288{289switch (calleeMethod->convertToMethod()->getMandatoryRecognizedMethod())290{291// call to invokeExactTargetAddress are generated out of thin air by our JSR292292// implementation, but we never want the VM or anyone else to know this so we must293// always inline the implementation294case TR::java_lang_invoke_MethodHandle_invokeExactTargetAddress:295{296TR::TreeTop *scanTT = callNodeTreeTop->getNextTreeTop();297TR::Node *nextCall = NULL;298299while (scanTT &&300scanTT->getNode()->getByteCodeInfo().getByteCodeIndex() == callNodeTreeTop->getNode()->getByteCodeInfo().getByteCodeIndex() &&301scanTT->getNode()->getByteCodeInfo().getCallerIndex() == callNodeTreeTop->getNode()->getByteCodeInfo().getCallerIndex())302{303TR::Node *scanNode = scanTT->getNode();304if (scanNode && (scanNode->getOpCode().isCheck() || scanNode->getOpCodeValue() == TR::treetop))305scanNode = scanNode->getFirstChild();306307if (scanNode->getOpCode().isCall())308{309nextCall = scanNode;310break;311}312scanTT = scanTT->getNextTreeTop();313}314315debugTrace(tracer(), "considering nextOperation node n%dn", nextCall->getGlobalIndex());316if (nextCall && nextCall->getOpCode().hasSymbolReference() &&317nextCall->getSymbolReference()->getSymbol()->getMethodSymbol()->isComputedVirtual())318return true;319}320default:321break;322}323}324return false;325}326327/** Test for methods that we wish to inline whenever possible.328329Identify methods for which the benefits of inlining them into the caller330are particularly significant and which might not otherwise be chosen by331the inliner.332*/333bool334TR_J9InlinerPolicy::alwaysWorthInlining(TR_ResolvedMethod * calleeMethod, TR::Node *callNode)335{336if (!calleeMethod)337return false;338339if (isInlineableJNI(calleeMethod, callNode))340return true;341342if (calleeMethod->isDAAWrapperMethod())343return true;344345if (isJSR292AlwaysWorthInlining(calleeMethod))346return true;347348switch (calleeMethod->getRecognizedMethod())349{350case TR::sun_misc_Unsafe_getAndAddLong:351case TR::sun_misc_Unsafe_getAndSetLong:352return comp()->target().is32Bit();353case TR::java_lang_J9VMInternals_fastIdentityHashCode:354case TR::java_lang_Class_getSuperclass:355case TR::java_lang_String_regionMatchesInternal:356case TR::java_lang_String_regionMatches:357case TR::java_lang_Class_newInstance:358// we rely on inlining compareAndSwap so we see the inner native call and can special case it359case TR::com_ibm_jit_JITHelpers_compareAndSwapIntInObject:360case TR::com_ibm_jit_JITHelpers_compareAndSwapLongInObject:361case TR::com_ibm_jit_JITHelpers_compareAndSwapObjectInObject:362case TR::com_ibm_jit_JITHelpers_compareAndSwapIntInArray:363case TR::com_ibm_jit_JITHelpers_compareAndSwapLongInArray:364case TR::com_ibm_jit_JITHelpers_compareAndSwapObjectInArray:365case TR::com_ibm_jit_JITHelpers_jitHelpers:366case TR::com_ibm_jit_JITHelpers_intrinsicIndexOfLatin1:367case TR::com_ibm_jit_JITHelpers_intrinsicIndexOfUTF16:368case TR::java_lang_String_charAt:369case TR::java_lang_String_charAtInternal_I:370case TR::java_lang_String_charAtInternal_IB:371case TR::java_lang_String_checkIndex:372case TR::java_lang_String_coder:373case TR::java_lang_String_isLatin1:374case TR::java_lang_String_length:375case TR::java_lang_String_lengthInternal:376case TR::java_lang_String_isCompressed:377case TR::java_lang_StringBuffer_capacityInternal:378case TR::java_lang_StringBuffer_lengthInternalUnsynchronized:379case TR::java_lang_StringBuilder_capacityInternal:380case TR::java_lang_StringBuilder_lengthInternal:381case TR::java_lang_StringUTF16_charAt:382case TR::java_lang_StringUTF16_checkIndex:383case TR::java_lang_StringUTF16_length:384case TR::java_lang_StringUTF16_newBytesFor:385case TR::java_util_HashMap_get:386case TR::java_util_HashMap_getNode:387case TR::java_lang_String_getChars_charArray:388case TR::java_lang_String_getChars_byteArray:389case TR::java_lang_Integer_toUnsignedLong:390case TR::java_nio_Bits_byteOrder:391case TR::java_nio_ByteOrder_nativeOrder:392return true;393394// In Java9 the following enum values match both sun.misc.Unsafe and395// jdk.internal.misc.Unsafe The sun.misc.Unsafe methods are simple396// wrappers to call jdk.internal impls, and we want to inline them. Since397// the same code can run with Java8 classes where sun.misc.Unsafe has the398// JNI impl, we need to differentiate by testing with isNative(). If it is399// native, then we don't need to inline it as it will be handled400// elsewhere.401case TR::sun_misc_Unsafe_compareAndSwapInt_jlObjectJII_Z:402case TR::sun_misc_Unsafe_compareAndSwapLong_jlObjectJJJ_Z:403case TR::sun_misc_Unsafe_compareAndSwapObject_jlObjectJjlObjectjlObject_Z:404case TR::sun_misc_Unsafe_copyMemory:405return !calleeMethod->isNative();406default:407break;408}409410if (!strncmp(calleeMethod->classNameChars(), "java/util/concurrent/atomic/", strlen("java/util/concurrent/atomic/")))411{412return true;413}414415int32_t length = calleeMethod->classNameLength();416char* className = calleeMethod->classNameChars();417418if (length == 24 && !strncmp(className, "jdk/internal/misc/Unsafe", 24))419return true;420else if (length == 15 && !strncmp(className, "sun/misc/Unsafe", 15))421return true;422423if (!comp()->getOption(TR_DisableForceInlineAnnotations) &&424comp()->fej9()->isForceInline(calleeMethod))425{426if (comp()->trace(OMR::inlining))427traceMsg(comp(), "@ForceInline was specified for %s, in alwaysWorthInlining\n", calleeMethod->signature(comp()->trMemory()));428return true;429}430431return false;432}433434/*435* Check if there is any method handle invoke left in the method body436*/437static bool checkForRemainingInlineableJSR292(TR::Compilation *comp, TR::ResolvedMethodSymbol *methodSymbol)438{439TR::NodeChecklist visited(comp);440for (TR::TreeTop *tt = methodSymbol->getFirstTreeTop(); tt ; tt = tt->getNextTreeTop())441{442TR::Node *ttNode = tt->getNode();443if (ttNode->getNumChildren() > 0)444{445TR::Node *node = ttNode->getFirstChild();446if (node->getOpCode().isCall() && !visited.contains(node))447{448visited.add(node);449if (node->getSymbolReference()->getSymbol()->getResolvedMethodSymbol())450{451TR_ResolvedMethod * resolvedMethod = node->getSymbolReference()->getSymbol()->getResolvedMethodSymbol()->getResolvedMethod();452if (!node->isTheVirtualCallNodeForAGuardedInlinedCall() &&453(comp->fej9()->isLambdaFormGeneratedMethod(resolvedMethod) ||454resolvedMethod->getRecognizedMethod() == TR::java_lang_invoke_MethodHandle_invokeBasic ||455resolvedMethod->convertToMethod()->isArchetypeSpecimen() ||456resolvedMethod->getRecognizedMethod() == TR::java_lang_invoke_MethodHandle_invokeExact))457{458return true;459}460}461}462}463}464return false;465}466467void468TR_J9InlinerUtil::requestAdditionalOptimizations(TR_CallTarget *calltarget)469{470if (calltarget->_myCallSite->getDepth() == -1 // only do this for top level callee to prevent exponential walk of inlined trees471&& checkForRemainingInlineableJSR292(comp(), calltarget->_calleeSymbol))472{473_inliner->getOptimizer()->setRequestOptimization(OMR::methodHandleInvokeInliningGroup);474if (comp()->trace(OMR::inlining))475heuristicTrace(tracer(),"Requesting one more pass of targeted inlining due to method handle invoke in %s\n", tracer()->traceSignature(calltarget->_calleeSymbol));476}477}478479void480TR_J9InlinerUtil::adjustByteCodeSize(TR_ResolvedMethod *calleeResolvedMethod, bool isInLoop, TR::Block *block, int &bytecodeSize)481{482traceMsg(comp(), "Reached new code \n");483int32_t blockNestingDepth = 1;484if (isInLoop)485{486char *tmptmp=0;487if (calleeResolvedMethod)488tmptmp = TR::Compiler->cls.classSignature(comp(), calleeResolvedMethod->containingClass(),trMemory());489490bool doit = false;491492if (((TR_J9InlinerPolicy *)inliner()->getPolicy())->aggressivelyInlineInLoops())493{494doit = true;495}496497if (doit && calleeResolvedMethod && !strcmp(tmptmp,"Ljava/math/BigDecimal;"))498{499traceMsg(comp(), "Reached code for block nesting depth %d\n", blockNestingDepth);500if ((isInLoop || (blockNestingDepth > 1)) &&501(bytecodeSize > 10))502{503if (comp()->trace(OMR::inlining))504heuristicTrace(tracer(),"Exceeds Size Threshold: Scaled down size for call block %d from %d to %d\n", block->getNumber(), bytecodeSize, 10);505bytecodeSize = 15;506}507}508else509heuristicTrace(tracer(),"Omitting Big Decimal method from size readjustment, calleeResolvedMethod = %p, tmptmp =%s",calleeResolvedMethod, tmptmp);510}511}512513TR::Node *514TR_J9InlinerPolicy::genCompressedRefs(TR::Node * address, bool genTT, int32_t isLoad)515{516static char *pEnv = feGetEnv("TR_UseTranslateInTrees");517518if (performTransformation(comp(), "O^O Inliner: Generating compressedRefs anchor for node [%p]\n", address))519{520TR::Node *value = address;521if (pEnv && (isLoad < 0)) // store522value = address->getSecondChild();523TR::Node *newAddress = TR::Node::createCompressedRefsAnchor(value);524//traceMsg(comp(), "compressedRefs anchor %p generated\n", newAddress);525if (!pEnv && genTT)526{527if (!newAddress->getOpCode().isTreeTop())528newAddress = TR::Node::create(TR::treetop, 1, newAddress);529}530else531return newAddress;532}533return NULL;534}535536537TR::Node *538TR_J9InlinerPolicy::createUnsafeAddressWithOffset(TR::Node * unsafeCall)539{540if (comp()->target().is64Bit())541{542TR::Node *constNode = TR::Node::lconst(unsafeCall, ~(J9_SUN_FIELD_OFFSET_MASK));543return TR::Node::create(TR::aladd, 2, unsafeCall->getChild(1), TR::Node::create(TR::land, 2, unsafeCall->getChild(2), constNode));544}545546return TR::Node::create(TR::aiadd, 2, unsafeCall->getChild(1), TR::Node::create(TR::iand, 2, TR::Node::create(TR::l2i, 1, unsafeCall->getChild(2)), TR::Node::iconst(unsafeCall, ~(J9_SUN_FIELD_OFFSET_MASK))));547}548549void550TR_J9InlinerPolicy::createTempsForUnsafeCall( TR::TreeTop *callNodeTreeTop, TR::Node * unsafeCallNode )551{552//This method is intended to replace and generalize createTempsForUnsafePutGet553//Will go through all children of the unsafeCallNode and create a store tree that child, insert it before the call, and then replace the call's child with a load of the symref.554555for (int32_t i = 0 ; i < unsafeCallNode->getNumChildren() ; ++i)556{557TR::Node *child = unsafeCallNode->getChild(i);558559560//create a store of the correct type and insert before call.561562TR::DataType dataType = child->getDataType();563TR::SymbolReference *newSymbolReference = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(), dataType);564565TR::Node *storeNode = TR::Node::createWithSymRef(comp()->il.opCodeForDirectStore(dataType), 1, 1, child, newSymbolReference);566TR::TreeTop *storeTree = TR::TreeTop::create(comp(), storeNode);567568debugTrace(tracer(),"Creating store node %p with child %p",storeNode,child);569570callNodeTreeTop->insertBefore(storeTree);571572// Replace the old child with a load of the new sym ref573TR::Node *value = TR::Node::createWithSymRef(child, comp()->il.opCodeForDirectLoad(dataType), 0, newSymbolReference);574575debugTrace(tracer(),"Replacing callnode %p child %p with %p",unsafeCallNode,unsafeCallNode->getChild(i),value);576577unsafeCallNode->setAndIncChild(i, value);578child->recursivelyDecReferenceCount();579580}581}582void583TR_J9InlinerPolicy::createTempsForUnsafePutGet(TR::Node*& unsafeAddress,584TR::Node* unsafeCall,585TR::TreeTop* callNodeTreeTop,586TR::Node*& offset,587TR::SymbolReference*& newSymbolReferenceForAddress,588bool isUnsafeGet)589{590TR::Node *oldUnsafeAddress = unsafeAddress;591TR::DataType dataType = unsafeAddress->getDataType();592TR::SymbolReference *newSymbolReference =593comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(), dataType);594newSymbolReferenceForAddress = newSymbolReference;595TR::Node *storeNode =596TR::Node::createWithSymRef(comp()->il.opCodeForDirectStore(unsafeAddress->getDataType()),5971, 1, unsafeAddress, newSymbolReference);598TR::TreeTop *storeTree = TR::TreeTop::create(comp(), storeNode);599600if (tracer()->debugLevel())601{602debugTrace(tracer(), "\tIn createTempsForUnsafePutGet. inserting store Tree before callNodeTT:\n");603comp()->getDebug()->print(comp()->getOutFile(), storeTree);604}605606callNodeTreeTop->insertTreeTopsBeforeMe(storeTree);607608// Replace the old child with a load of the new sym ref609unsafeAddress =610TR::Node::createWithSymRef(unsafeAddress,611comp()->il.opCodeForDirectLoad(unsafeAddress->getDataType()),6120, newSymbolReference);613614debugTrace(tracer(), "\tIn createTempsForUnsafePutGet. replacing unsafeCall ( %p) child %p with %p\n", unsafeCall, unsafeCall->getChild(1), unsafeAddress);615616unsafeCall->setAndIncChild(1, unsafeAddress);617618TR::Node *oldOffset = offset;619dataType = offset->getDataType();620newSymbolReference = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(),621dataType);622storeNode = TR::Node::createWithSymRef(comp()->il.opCodeForDirectStore(offset->getDataType()),6231, 1, offset, newSymbolReference);624storeTree = TR::TreeTop::create(comp(), storeNode);625626if (tracer()->debugLevel())627{628traceMsg(comp(), "\tIn createTempsForUnsafePutGet. inserting store Tree before callNodeTT 2:\n");629comp()->getDebug()->print(comp()->getOutFile(), storeTree);630}631632callNodeTreeTop->insertTreeTopsBeforeMe(storeTree);633634// Replace the old child with a load of the new sym ref635offset = TR::Node::createWithSymRef(offset,636comp()->il.opCodeForDirectLoad(offset->getDataType()),6370, newSymbolReference);638639debugTrace(tracer(), "\tIn createTempsForUnsafePutGet. replacing unsafeCall ( %p) child %p with %p\n", unsafeCall, unsafeCall->getChild(2), offset);640641unsafeCall->setAndIncChild(2, offset);642if (!isUnsafeGet)643{644TR::Node *value = unsafeCall->getChild(3);645TR::Node *oldValue = value;646dataType = value->getDataType();647newSymbolReference =648comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(), dataType);649storeNode = TR::Node::createWithSymRef(comp()->il.opCodeForDirectStore(value->getDataType()), 1, 1, value, newSymbolReference);650storeTree = TR::TreeTop::create(comp(), storeNode);651callNodeTreeTop->insertTreeTopsBeforeMe(storeTree);652653// Replace the old child with a load of the new sym ref654value = TR::Node::createWithSymRef(value,655comp()->il.opCodeForDirectLoad(value->getDataType()),6560, newSymbolReference);657unsafeCall->setAndIncChild(3, value);658oldValue->recursivelyDecReferenceCount();659}660661oldUnsafeAddress->recursivelyDecReferenceCount();662oldOffset->recursivelyDecReferenceCount();663}664// Extra boolean is for AOT case when we can not simplify the Class Test so we need Array Case in that scenario, But we can put indirect in cold instead of fallthrough for the tests665TR::TreeTop*666TR_J9InlinerPolicy::genClassCheckForUnsafeGetPut(TR::Node* offset, bool isNotLowTagged)667{668// The low bit is tagged if the object being dereferenced is a669// java/lang/Class object. This is because this is a special case when670// an extra level of indirection is necessary671bool isILoad = (offset->getOpCodeValue() == TR::iload);672TR::Node *lowTag = NULL;673674if (isILoad)675lowTag = TR::Node::create(TR::iand, 2, offset, TR::Node::iconst(1));676else677lowTag = TR::Node::create(TR::land, 2, offset, TR::Node::lconst(1));678679TR::ILOpCodes op = isNotLowTagged ? (isILoad ? TR::ificmpne : TR::iflcmpne) : (isILoad ? TR::ificmpeq : TR::iflcmpeq);680// Create the if to check if an extra level of indirection is needed681TR::Node *cmp = TR::Node::createif(op, lowTag, lowTag->getSecondChild(), NULL);682TR::TreeTop* lowTagCmpTree = TR::TreeTop::create(comp(), cmp);683return lowTagCmpTree;684}685686687TR::TreeTop*688TR_J9InlinerPolicy::genClassCheckForUnsafeGetPut(TR::Node* offset)689{690// The low bit is tagged if the object being dereferenced is a691// java/lang/Class object. This is because this is a special case when692// an extra level of indirection is necessary693bool isILoad = (offset->getOpCodeValue() == TR::iload);694TR::Node *lowTag =695TR::Node::create(isILoad ? TR::iand : TR::land, 2, offset,696TR::Node::create(offset, isILoad ? TR::iconst : TR::lconst, 0, 0));697if (isILoad)698lowTag->getSecondChild()->setInt(1);699else700lowTag->getSecondChild()->setLongInt(1);701702// Create the if to check if an extra level of indirection is needed703TR::Node *cmp = TR::Node::createif(isILoad ? TR::ificmpne : TR::iflcmpne,704lowTag, lowTag->getSecondChild(), NULL);705TR::TreeTop* lowTagCmpTree = TR::TreeTop::create(comp(), cmp);706return lowTagCmpTree;707}708709710TR::TreeTop*711TR_J9InlinerPolicy::genDirectAccessCodeForUnsafeGetPut(TR::Node* callNode,712bool conversionNeeded, bool isUnsafeGet)713{714//Generate the code for the direct access715TR::Node *directAccessNode = callNode->duplicateTree();716TR::TreeTop *directAccessTreeTop = TR::TreeTop::create(comp(), directAccessNode, NULL, NULL);717TR::Node* firstChild = directAccessNode->getFirstChild();718719if (isUnsafeGet) {720firstChild = firstChild->getFirstChild();721//if there is a conversion node we need to go one level deeper722if (conversionNeeded)723firstChild = firstChild->getFirstChild();724}725else {726// if there is an anchor, the store is one level below727if (directAccessNode->getOpCodeValue() == TR::compressedRefs)728firstChild = firstChild->getFirstChild();729}730731TR_ASSERT(((firstChild->getOpCodeValue() == TR::aiadd) ||732(firstChild->getOpCodeValue() == TR::aladd)), "Unexpected opcode in unsafe access\n");733TR::Node *grandChild = firstChild->getSecondChild();734firstChild->setAndIncChild(1, grandChild->getFirstChild());735grandChild->recursivelyDecReferenceCount();736737// If a conversion is needed, the 'callNode' was constructed earlier on in createUnsafe(get/put)WithOffset738// While some of the children end up in the final trees, this constructed callNode does not.739// We need to dec the reference count otherwise a child of the callNode that ends up in the final trees will have an extra refcount and will cause740// an assert741if(conversionNeeded)742{743for(int32_t i=0 ; i< callNode->getNumChildren(); i++)744{745debugTrace(tracer(), "\t In genDirectAccessCodeForUnsafeGetPut, recursively dec'ing refcount of %p:\n", callNode->getChild(i));746747callNode->getChild(i)->recursivelyDecReferenceCount();748}749}750751return directAccessTreeTop;752}753754755TR::TreeTop*756TR_J9InlinerPolicy::genIndirectAccessCodeForUnsafeGetPut(TR::Node* directAccessOrTempStoreNode, TR::Node* unsafeAddress)757{758// Generate the indirect access code in the java/lang/Class case. First modify unsafeAddress which is a descendant759// of directAccessOrTempStoreNode and then make a copy of directAccessOrTempStoreNode.760TR::Node *oldAddressFirstChild = unsafeAddress->getFirstChild();761TR::Node *addressFirstChild =762TR::Node::createWithSymRef(TR::aloadi, 1, 1, oldAddressFirstChild,763comp()->getSymRefTab()->findOrCreateClassFromJavaLangClassSymbolRef());764addressFirstChild =765TR::Node::createWithSymRef(TR::aloadi, 1, 1, addressFirstChild,766comp()->getSymRefTab()->findOrCreateRamStaticsFromClassSymbolRef());767unsafeAddress->setAndIncChild(0, addressFirstChild);768oldAddressFirstChild->recursivelyDecReferenceCount();769770TR::Node* indirectAccessOrTempStoreNode = directAccessOrTempStoreNode->duplicateTree();771772// The directAccessNode has been replaced with the corresponding get (load)/put (store) node at this point. The773// purpose of this function is to create the indirect access (static access) for an unsafe get/put operation774// since in general we do not know whether the target of our get/put operation is to a static or instance field.775// As such for the indirect access (static access) case we need to reassign the symbol reference after duplicating776// the direct access node.777778TR::Symbol* directSymbol = directAccessOrTempStoreNode->getSymbolReference()->getSymbol();779780if (!directSymbol->isUnsafeShadowSymbol())781{782// We may have generated a store to a temp in case of a get operation783directSymbol = directAccessOrTempStoreNode->getFirstChild()->getSymbolReference()->getSymbol();784}785786// Sanity check. Note this is fatal because under concurrent scavenge we could potentially miss a read barrier here.787TR_ASSERT_FATAL(directSymbol->isUnsafeShadowSymbol(), "Expected to find an unsafe symbol for the get/put operation.");788789TR::Node* indirectAccessNode = indirectAccessOrTempStoreNode;790791TR::Symbol* indirectSymbol = indirectAccessOrTempStoreNode->getSymbolReference()->getSymbol();792793if (!indirectSymbol->isUnsafeShadowSymbol())794{795// We may have generated a store to a temp in case of a get operation796indirectAccessNode = indirectAccessOrTempStoreNode->getFirstChild();797}798799TR::SymbolReference* indirectSymRef = comp()->getSymRefTab()->findOrCreateUnsafeSymbolRef(directSymbol->getDataType(), true, true, directSymbol->isVolatile());800801indirectAccessNode->setSymbolReference(indirectSymRef);802803return TR::TreeTop::create(comp(), indirectAccessOrTempStoreNode, NULL, NULL);804}805806TR::Block *807TR_J9InlinerPolicy::addNullCheckForUnsafeGetPut(TR::Node* unsafeAddress,808TR::SymbolReference* newSymbolReferenceForAddress,809TR::TreeTop* callNodeTreeTop,810TR::TreeTop* directAccessTreeTop,811TR::TreeTop* arrayDirectAccessTreeTop,812TR::TreeTop* indirectAccessTreeTop)813{814//Generate the treetop for the null comparison815TR::Node *addrLoad =816TR::Node::createWithSymRef(unsafeAddress,817comp()->il.opCodeForDirectLoad(unsafeAddress->getDataType()),8180, newSymbolReferenceForAddress);819TR::Node *nullCmp =820TR::Node::createif(TR::ifacmpeq, addrLoad,821TR::Node::create(addrLoad, TR::aconst, 0, 0), NULL);822TR::TreeTop *nullComparisonTree = TR::TreeTop::create(comp(), nullCmp, NULL, NULL);823TR::TreeTop* ifTree = arrayDirectAccessTreeTop ? arrayDirectAccessTreeTop : indirectAccessTreeTop;824TR::TreeTop* elseTree = arrayDirectAccessTreeTop ? indirectAccessTreeTop : directAccessTreeTop;825// Connect the trees/add blocks etc. properly and split the original block826TR::Block * joinBlock =827callNodeTreeTop->getEnclosingBlock()->828createConditionalBlocksBeforeTree(callNodeTreeTop,829nullComparisonTree,830ifTree,831elseTree,832comp()->getFlowGraph(), false, false);833return joinBlock;834}835836void837TR_J9InlinerPolicy::createAnchorNodesForUnsafeGetPut(TR::TreeTop* treeTop,838TR::DataType type, bool isUnsafeGet)839{840if (comp()->useCompressedPointers() && (type == TR::Address))841{842// create the anchor node only for the non-tagged case843844TR::Node* node = treeTop->getNode();845TR::TreeTop *compRefTT =846TR::TreeTop::create(comp(), genCompressedRefs(isUnsafeGet?node->getFirstChild():node,847false));848if (compRefTT)849{850TR::TreeTop *prevTT = treeTop->getPrevTreeTop();851prevTT->join(compRefTT);852compRefTT->join(isUnsafeGet?treeTop:treeTop->getNextTreeTop());853}854}855}856857void858TR_J9InlinerPolicy::genCodeForUnsafeGetPut(TR::Node* unsafeAddress,859TR::TreeTop* callNodeTreeTop,860TR::TreeTop* prevTreeTop,861TR::SymbolReference* newSymbolReferenceForAddress,862TR::TreeTop* directAccessTreeTop,863TR::TreeTop* lowTagCmpTree,864bool needNullCheck, bool isUnsafeGet,865bool conversionNeeded,866TR::Block * joinBlock,867TR_OpaqueClassBlock *javaLangClass,868TR::Node* orderedCallNode = NULL)869{870TR::CFG *cfg = comp()->getFlowGraph();871TR::Block *nullComparisonBlock = prevTreeTop->getEnclosingBlock();872TR::TreeTop* nullComparisonTree = nullComparisonBlock->getLastRealTreeTop();873TR::TreeTop *nullComparisonEntryTree = nullComparisonBlock->getEntry();874TR::TreeTop *nullComparisonExitTree = nullComparisonBlock->getExit();875//if conversionNeeded is true, we haven't generated and we don't need arrayDirectAccessBlock876TR::Block *arrayDirectAccessBlock = conversionNeeded ? nullComparisonTree->getNode()->getBranchDestination()->getNode()->getBlock() : NULL;877TR::Block *indirectAccessBlock;878TR::Block * directAccessBlock;879if (conversionNeeded)880{881//Generating block for direct access882indirectAccessBlock = nullComparisonBlock->getNextBlock();883directAccessBlock = TR::Block::createEmptyBlock(lowTagCmpTree->getNode(), comp(),884indirectAccessBlock->getFrequency());885directAccessBlock->append(directAccessTreeTop);886directAccessBlock->append(TR::TreeTop::create(comp(),887TR::Node::create(directAccessTreeTop->getNode(),888TR::Goto, 0, joinBlock->getEntry())));889arrayDirectAccessBlock->getExit()->insertTreeTopsAfterMe(directAccessBlock->getEntry(),890directAccessBlock->getExit());891cfg->addNode(directAccessBlock);892cfg->addEdge(TR::CFGEdge::createEdge(directAccessBlock, joinBlock, trMemory()));893}894else895{896directAccessBlock = nullComparisonBlock->getNextBlock();897indirectAccessBlock = nullComparisonTree->getNode()->getBranchDestination()->getNode()->getBlock();898indirectAccessBlock->setFrequency(VERSIONED_COLD_BLOCK_COUNT);899indirectAccessBlock->setIsCold();900nullComparisonTree->getNode()->setBranchDestination(directAccessBlock->getEntry());901}902903debugTrace(tracer(), "\t In genCodeForUnsafeGetPut, Block %d created for direct Access\n", directAccessBlock->getNumber());904905//Generating block for lowTagCmpTree906TR::Block *lowTagCmpBlock =907TR::Block::createEmptyBlock(unsafeAddress, comp(), conversionNeeded ? indirectAccessBlock->getFrequency() : directAccessBlock->getFrequency());908lowTagCmpBlock->append(lowTagCmpTree);909cfg->addNode(lowTagCmpBlock);910debugTrace(tracer(), "\t In genCodeForUnsafeGetPut, Block %d created for low tag comparison\n", lowTagCmpBlock->getNumber());911912TR::Node *vftLoad = TR::Node::createWithSymRef(TR::aloadi, 1, 1, TR::Node::createWithSymRef(unsafeAddress, comp()->il.opCodeForDirectLoad(unsafeAddress->getDataType()), 0, newSymbolReferenceForAddress), comp()->getSymRefTab()->findOrCreateVftSymbolRef());913TR::TreeTop *isArrayTreeTop;914TR::Block *isArrayBlock;915TR::TreeTop *isClassTreeTop;916TR::Block *isClassBlock;917// If we need conversion or java/lang/Class is not loaded yet, we generate old sequence of tests918if (conversionNeeded || javaLangClass == NULL)919{920TR::Node *isArrayField = NULL;921if (comp()->target().is32Bit())922{923isArrayField = TR::Node::createWithSymRef(TR::iloadi, 1, 1, vftLoad, comp()->getSymRefTab()->findOrCreateClassAndDepthFlagsSymbolRef());924}925else926{927isArrayField = TR::Node::createWithSymRef(TR::lloadi, 1, 1, vftLoad, comp()->getSymRefTab()->findOrCreateClassAndDepthFlagsSymbolRef());928isArrayField = TR::Node::create(TR::l2i, 1, isArrayField);929}930TR::Node *andConstNode = TR::Node::create(isArrayField, TR::iconst, 0, TR::Compiler->cls.flagValueForArrayCheck(comp()));931TR::Node * andNode = TR::Node::create(TR::iand, 2, isArrayField, andConstNode);932TR::Node *isArrayNode = TR::Node::createif(TR::ificmpeq, andNode, andConstNode, NULL);933isArrayTreeTop = TR::TreeTop::create(comp(), isArrayNode, NULL, NULL);934isArrayBlock = TR::Block::createEmptyBlock(vftLoad, comp(), indirectAccessBlock->getFrequency());935isArrayBlock->append(isArrayTreeTop);936cfg->addNode(isArrayBlock);937isArrayNode->setBranchDestination(conversionNeeded ? arrayDirectAccessBlock->getEntry() : directAccessBlock->getEntry());938if (conversionNeeded)939{940indirectAccessBlock->getEntry()->insertTreeTopsBeforeMe(lowTagCmpBlock->getEntry(), lowTagCmpBlock->getExit());941lowTagCmpTree->getNode()->setBranchDestination(directAccessBlock->getEntry());942}943else944{945traceMsg(comp(),"\t\t Generating an isArray test as j9class of java/lang/Class is NULL");946directAccessBlock->getEntry()->insertTreeTopsBeforeMe(lowTagCmpBlock->getEntry(), lowTagCmpBlock->getExit());947lowTagCmpTree->getNode()->setBranchDestination(indirectAccessBlock->getEntry());948}949lowTagCmpBlock->getEntry()->insertTreeTopsBeforeMe(isArrayBlock->getEntry(),950isArrayBlock->getExit());951cfg->addEdge(TR::CFGEdge::createEdge(isArrayBlock, lowTagCmpBlock, trMemory()));952cfg->addEdge(TR::CFGEdge::createEdge(lowTagCmpBlock, indirectAccessBlock, trMemory()));953cfg->addEdge(TR::CFGEdge::createEdge(isArrayBlock, conversionNeeded ? arrayDirectAccessBlock : directAccessBlock, trMemory()));954cfg->addEdge(TR::CFGEdge::createEdge(nullComparisonBlock, isArrayBlock, trMemory()));955956debugTrace(tracer(), "\t In genCodeForUnsafeGetPut, Block %d created for array check\n", isArrayBlock->getNumber());957}958else959{960// Following sequence of code generate isClassTest.961// ifacmpeq goto indirectAccess962// aload vft-symbol963// aconst J9Class of java/lang/Class964965// Note for loadJavaLangClass node:966// AOT Relocation relies on guards to locate correct method for a call site, while inlined Unsafe calls do not have a guard.967// Therefore J9Class of java/lang/Class cannot be relocated correctly. Inserting any guard for an inlined Unsafe call is potentially968// expensive, especially for applications that intensively use Unsafe, such as Apache Spark.969// As a compromise, the node is given such BCI as if it is generated from the out-most call, so that J9Class can be correctly970// relocated without any guard.971TR::Node *loadJavaLangClass = TR::Node::createAddressNode(vftLoad, TR::aconst,(uintptr_t) javaLangClass);972loadJavaLangClass->getByteCodeInfo().setInvalidCallerIndex();973loadJavaLangClass->getByteCodeInfo().setZeroByteCodeIndex();974loadJavaLangClass->setIsClassPointerConstant(true);975976TR::Node *isClassNode = TR::Node::createif(TR::ifacmpeq, vftLoad, loadJavaLangClass, NULL);977isClassTreeTop = TR::TreeTop::create(comp(), isClassNode, NULL, NULL);978isClassBlock = TR::Block::createEmptyBlock(vftLoad, comp(), directAccessBlock->getFrequency());979isClassBlock->append(isClassTreeTop);980cfg->addNode(isClassBlock);981directAccessBlock->getEntry()->insertTreeTopsBeforeMe(isClassBlock->getEntry(), isClassBlock->getExit());982lowTagCmpTree->getNode()->setBranchDestination(directAccessBlock->getEntry());983isClassNode->setBranchDestination(indirectAccessBlock->getEntry());984isClassBlock->getEntry()->insertTreeTopsBeforeMe(lowTagCmpBlock->getEntry(), lowTagCmpBlock->getExit());985cfg->addEdge(TR::CFGEdge::createEdge(isClassBlock,directAccessBlock, trMemory()));986cfg->addEdge(TR::CFGEdge::createEdge(isClassBlock,indirectAccessBlock, trMemory()));987cfg->addEdge(TR::CFGEdge::createEdge(nullComparisonBlock, lowTagCmpBlock, trMemory()));988cfg->addEdge(TR::CFGEdge::createEdge(lowTagCmpBlock, isClassBlock, trMemory()));989990debugTrace(tracer(), "\t In genCodeForUnsafeGetPut, Block %d created for isClass Test\n", isClassBlock->getNumber());991}992cfg->addEdge(TR::CFGEdge::createEdge(lowTagCmpBlock, directAccessBlock, trMemory()));993//Generating treetop and block for array check994cfg->removeEdge(nullComparisonBlock, indirectAccessBlock);995if (needNullCheck)996{997TR::TreeTop *treeBeforeCmp = nullComparisonTree->getPrevTreeTop();998TR::TreeTop *nullchkTree =999TR::TreeTop::create(comp(), treeBeforeCmp,1000TR::Node::createWithSymRef(TR::NULLCHK, 1, 1,1001TR::Node::create(TR::PassThrough, 1,1002TR::Node::createWithSymRef(unsafeAddress,1003comp()->il.opCodeForDirectLoad(unsafeAddress->getDataType()),10040, newSymbolReferenceForAddress)),1005comp()->getSymRefTab()->findOrCreateNullCheckSymbolRef(comp()->getMethodSymbol())1006)1007);1008nullchkTree->getNode()->getByteCodeInfo().setCallerIndex(comp()->getCurrentInlinedSiteIndex());1009}10101011if (!isUnsafeGet && joinBlock && orderedCallNode)1012{1013TR::TreeTop *orderedCallTree = TR::TreeTop::create(comp(), orderedCallNode);1014joinBlock->prepend(orderedCallTree);1015}1016}10171018/*1019Converting Unsafe.get/put* routines into inlined code involves two cases:10201) if the size of the element to put/get is 4 bytes or more10212) if the size of the element to put/get is less than 4 bytes (boolean, byte, char, short)10221023In (1), there are two alternatives on how to read from/write to the object: direct and1024indirect write/read. The selection of alternatives is done by looking at three conditions:1025a) whether the object is NULL1026b) whether the object is array1027c) whether the object is of type java.lang.Class1028The pseudocode of the generated inline code for case (1) under normal compilation is :1029if (object == NULL)1030use direct access1031else if (offset is not low tagged)1032use direct access1033else if (object is type of java/lang/Class)1034use indirect access1035else1036use direct access10371038If we can not get the J9Class of java/lang/Class, we generate following sequence of tests1039if (object == NULL)1040use direct access1041else if (object it Array type)1042use direct access1043else if (offset is low tagged)1044use indirect access1045else1046use direct access104710481049In (2), there are three alternatives on how to read from/write the object. direct,1050direct with conversion, indirect. The same three conditions are used to decide which one1051to use based on the following pseudocode:1052if (object is NULL)1053use direct access with conversion1054else if (object is array)1055use direct access with conversion1056else if (object is of type Class)1057use indirect access1058else1059use direct access10601061- genClassCheckForUnsafeGetPut builds the treetop for condition (c) above.1062- genDirectAccessCodeForUnsafeGetPut completes the building of treetop for both "direct access" and1063"direct access with conversion"1064- genIndirectAccessCodeForUnsafeGetPut builds the treetop for indirect access1065- addNullCheckForUnsafeGetPut builds node for NULLness check (condition (a) above) and1066builds a diamond CFG based on that. The CFG will be completed in later stages.1067- createAnchorNodesForUnsafeGetPut creates compressed references in case they are needed1068- genCodeForUnsafeGetPut completes the CFG/code by adding the array check, Class check,1069and the direct access code.10701071Note that in case (2), i.e., when the conversion is needed, we generate code like the1072following for the "direct access with conversion" for Unsafe.getByte1073b2i1074ibload1075aiadd1076while the direct access code looks like1077iiload1078aiadd1079We will replace b2i and ibload by c2iu and icload for Unsafe.getChar, by1080s2i and isload for Unsafe.getShort, and by bu2i and ibload for Unsafe.getBoolean10811082For Unsafe.putByte and Unsafe.putBoolean, we generate1083ibstore1084i2b1085<some load node>1086We replace i2b and ibstore by i2c and icstore for Unsafe.getChar, and by i2s and isstore for1087Unsafe.getShort.1088*/10891090bool1091TR_J9InlinerPolicy::createUnsafePutWithOffset(TR::ResolvedMethodSymbol *calleeSymbol, TR::ResolvedMethodSymbol *callerSymbol, TR::TreeTop * callNodeTreeTop, TR::Node * unsafeCall, TR::DataType type, bool isVolatile, bool needNullCheck, bool isOrdered)1092{1093if (isVolatile && type == TR::Int64 && comp()->target().is32Bit() && !comp()->cg()->getSupportsInlinedAtomicLongVolatiles())1094return false;1095if (debug("traceUnsafe"))1096printf("createUnsafePutWithOffset %d in %s\n", type.getDataType(), comp()->signature());10971098debugTrace(tracer(), "\tcreateUnsafePutWithOffset. call tree %p offset(datatype) %d isvolatile %d needNullCheck %d isOrdered %d\n", callNodeTreeTop, type.getDataType(), isVolatile, needNullCheck, isOrdered);10991100// Truncate the value before inlining the call1101if (TR_J9MethodBase::isUnsafeGetPutBoolean(calleeSymbol->getRecognizedMethod()))1102{1103TR::TransformUtil::truncateBooleanForUnsafeGetPut(comp(), callNodeTreeTop);1104}11051106// Preserve null check on the unsafe object1107TR::TransformUtil::separateNullCheck(comp(), callNodeTreeTop, tracer()->debugLevel());11081109// Since the block has to be split, we need to create temps for the arguments to the call1110for (int i = 0; i < unsafeCall->getNumChildren(); i++)1111{1112TR::Node* child = unsafeCall->getChild(i);1113TR::Node* newChild = TR::TransformUtil::saveNodeToTempSlot(comp(), child, callNodeTreeTop);1114unsafeCall->setAndIncChild(i, newChild);1115child->recursivelyDecReferenceCount();1116}11171118TR::Node *offset = unsafeCall->getChild(2);1119TR::TreeTop *prevTreeTop = callNodeTreeTop->getPrevTreeTop();1120TR::SymbolReference *newSymbolReferenceForAddress = unsafeCall->getChild(1)->getSymbolReference();1121TR::SymbolReference * symRef = comp()->getSymRefTab()->findOrCreateUnsafeSymbolRef(type, true, false, isVolatile);1122TR::Node *orderedCallNode = NULL;11231124if (isOrdered)1125{1126symRef->getSymbol()->setOrdered();1127orderedCallNode = callNodeTreeTop->getNode()->duplicateTree();1128orderedCallNode->getFirstChild()->setDontInlinePutOrderedCall();11291130debugTrace(tracer(), "\t Duplicate Tree for ordered call, orderedCallNode = %p\n", orderedCallNode);1131}11321133static char *disableIllegalWriteReport = feGetEnv("TR_DisableIllegalWriteReport");1134TR::TreeTop* reportFinalFieldModification = NULL;1135if (!disableIllegalWriteReport && !comp()->getOption(TR_DisableGuardedStaticFinalFieldFolding))1136{1137reportFinalFieldModification = TR::TransformUtil::generateReportFinalFieldModificationCallTree(comp(), unsafeCall->getArgument(1)->duplicateTree());1138}11391140TR::Node * unsafeAddress = createUnsafeAddressWithOffset(unsafeCall);1141if (tracer()->debugLevel())1142{1143debugTrace(tracer(), "\t After createUnsafeAddressWithOffset, unsafeAddress = %p : \n", unsafeAddress);1144TR::TreeTop *tmpUnsafeAddressTT = TR::TreeTop::create(comp(), unsafeAddress);1145comp()->getDebug()->print(comp()->getOutFile(), tmpUnsafeAddressTT);1146}11471148TR::Node* valueWithoutConversion = unsafeCall->getChild(3);1149TR::Node* valueWithConversion = NULL;1150TR::Node* unsafeNodeWithConversion = NULL;11511152debugTrace(tracer(), "\tvalueWithouTConversion = %p\n", valueWithoutConversion);115311541155bool conversionNeeded = comp()->fe()->dataTypeForLoadOrStore(type) != type;1156if (conversionNeeded)1157{1158TR::ILOpCodes conversionOpCode =1159TR::ILOpCode::getProperConversion(comp()->fe()->dataTypeForLoadOrStore(type), type, true);1160TR::Node* conversionNode = TR::Node::create(conversionOpCode,11611, valueWithoutConversion);1162valueWithConversion = conversionNode;1163unsafeNodeWithConversion = type == TR::Address && (TR::Compiler->om.writeBarrierType() != gc_modron_wrtbar_none)1164? TR::Node::createWithSymRef(TR::awrtbari, 3, 3, unsafeAddress, valueWithConversion, unsafeCall->getChild(1), symRef)1165: TR::Node::createWithSymRef(comp()->il.opCodeForIndirectArrayStore(type), 2, 2, unsafeAddress, valueWithConversion, symRef);11661167debugTrace(tracer(), "\tConversion is Needed, conversionNode = %p unsafeNodeWithConversion = %p valueWithConversion = %p\n", conversionNode, unsafeNodeWithConversion, valueWithConversion);11681169}1170TR::Node * unsafeNode = type == TR::Address && (TR::Compiler->om.writeBarrierType() != gc_modron_wrtbar_none)1171? TR::Node::createWithSymRef(TR::awrtbari, 3, 3, unsafeAddress, valueWithoutConversion, unsafeCall->getChild(1), symRef)1172: TR::Node::createWithSymRef(comp()->il.opCodeForIndirectStore(type), 2, 2, unsafeAddress, valueWithoutConversion, symRef);117311741175TR::TreeTop *oldCallNodeTreeTop = 0; // For Tracing Purposes Only1176if (tracer()->debugLevel())1177oldCallNodeTreeTop = TR::TreeTop::create(comp(),unsafeCall);11781179callNodeTreeTop->setNode(unsafeNode);11801181if (tracer()->debugLevel())1182{1183debugTrace(tracer(), "\t After callNodeTreeTop setNode callNodeTreeTop dump:\n");1184comp()->getDebug()->print(comp()->getOutFile(), callNodeTreeTop);1185debugTrace(tracer(), "\t After callNodeTreeTop setNode oldCallNodeTreeTop dump oldCallNodeTreeTop->getNode->getChild = %p:\n", oldCallNodeTreeTop->getNode() ? oldCallNodeTreeTop->getNode()->getFirstChild() : 0);1186comp()->getDebug()->print(comp()->getOutFile(), oldCallNodeTreeTop);1187}118811891190TR::TreeTop* directAccessTreeTop = genDirectAccessCodeForUnsafeGetPut(unsafeNode, false, false);11911192if (tracer()->debugLevel())1193{1194debugTrace(tracer(), "\t After genDirectAccessCodeForUnsafeGetPut, directAccessTreeTop dump:\n");1195comp()->getDebug()->print(comp()->getOutFile(), directAccessTreeTop);1196}11971198TR::TreeTop* arrayDirectAccessTreeTop = conversionNeeded1199? genDirectAccessCodeForUnsafeGetPut(unsafeNodeWithConversion, conversionNeeded, false)1200: NULL;12011202if (tracer()->debugLevel() && conversionNeeded)1203{1204debugTrace(tracer(), "\t After genDirectAccessCodeForUnsafeGetPut, arrayDirectAccessTreeTop dump:\n");1205comp()->getDebug()->print(comp()->getOutFile(), arrayDirectAccessTreeTop);1206}12071208TR::TreeTop* indirectAccessTreeTop = genIndirectAccessCodeForUnsafeGetPut(callNodeTreeTop->getNode(), unsafeAddress);12091210if (tracer()->debugLevel())1211{1212debugTrace(tracer(), "\t After genIndirectAccessCodeForUnsafeGetPut, indirectAccessTreeTop dump:\n");1213comp()->getDebug()->print(comp()->getOutFile(), indirectAccessTreeTop);1214}12151216if (indirectAccessTreeTop && indirectAccessTreeTop->getNode() && indirectAccessTreeTop->getNode()->getOpCode().isWrtBar())1217{1218debugTrace(tracer(), "Setting node %p as an unsafe static wrtbar\n", indirectAccessTreeTop->getNode());1219indirectAccessTreeTop->getNode()->setIsUnsafeStaticWrtBar(true);1220}12211222TR_OpaqueClassBlock *javaLangClass = comp()->getClassClassPointer(/* isVettedForAOT = */ true);1223// If we are not able to get javaLangClass it is still inefficient to put direct Access far1224// So in that case we will generate lowTagCmpTest to branch to indirect access if true1225bool needNotLowTagged = javaLangClass != NULL || conversionNeeded ;1226TR::TreeTop *lowTagCmpTree = genClassCheckForUnsafeGetPut(offset, needNotLowTagged);12271228if (tracer()->debugLevel())1229{1230debugTrace(tracer(), "\t After genClassCheckForUnsafeGetPut, lowTagCmpTree dump:\n");1231comp()->getDebug()->print(comp()->getOutFile(), lowTagCmpTree);1232}12331234TR::Block * joinBlock =1235addNullCheckForUnsafeGetPut(unsafeAddress, newSymbolReferenceForAddress,1236callNodeTreeTop, directAccessTreeTop,1237arrayDirectAccessTreeTop,1238indirectAccessTreeTop);12391240debugTrace(tracer(), "\t After addNullCHeckForUnsafeGetPut, joinBlock is %d\n", joinBlock->getNumber());12411242createAnchorNodesForUnsafeGetPut(directAccessTreeTop, type, false);1243if (arrayDirectAccessTreeTop)1244createAnchorNodesForUnsafeGetPut(arrayDirectAccessTreeTop, type, false);1245genCodeForUnsafeGetPut(unsafeAddress, callNodeTreeTop,1246prevTreeTop, newSymbolReferenceForAddress,1247directAccessTreeTop,1248lowTagCmpTree, needNullCheck, false, conversionNeeded,1249joinBlock, javaLangClass, orderedCallNode);125012511252// Test for static final field1253if (reportFinalFieldModification)1254{1255TR::Block* storeToStaticFieldBlock = indirectAccessTreeTop->getEnclosingBlock();1256auto isFinalStaticNode = TR::Node::createif(TR::iflcmpeq,1257TR::Node::create(TR::land, 2, offset->duplicateTree(), TR::Node::lconst(J9_SUN_FINAL_FIELD_OFFSET_TAG)),1258TR::Node::lconst(J9_SUN_FINAL_FIELD_OFFSET_TAG),1259NULL /*branchTarget*/);1260auto isFinalStaticTreeTop = TR::TreeTop::create(comp(), isFinalStaticNode);12611262TR::TransformUtil::createConditionalAlternatePath(comp(), isFinalStaticTreeTop, reportFinalFieldModification, storeToStaticFieldBlock, storeToStaticFieldBlock, comp()->getMethodSymbol()->getFlowGraph(), true /*markCold*/);12631264debugTrace(tracer(), "Created isFinal test node n%dn whose branch target is Block_%d to report illegal write to static final field\n",1265isFinalStaticNode->getGlobalIndex(), reportFinalFieldModification->getEnclosingBlock()->getNumber());12661267TR::DebugCounter::prependDebugCounter(comp(),1268TR::DebugCounter::debugCounterName(comp(),1269"illegalWriteReport/put/(%s %s)",1270comp()->signature(),1271comp()->getHotnessName(comp()->getMethodHotness())),1272reportFinalFieldModification->getNextTreeTop());12731274}12751276unsafeCall->recursivelyDecReferenceCount();1277return true;1278}127912801281TR::Node *1282TR_J9InlinerPolicy::createUnsafeMonitorOp(TR::ResolvedMethodSymbol *calleeSymbol, TR::ResolvedMethodSymbol *callerSymbol, TR::TreeTop * callNodeTreeTop, TR::Node * unsafeCall, bool isEnter)1283{1284bool isDirectJNI = unsafeCall->isPreparedForDirectJNI();1285// Expecting directToJNI to have loadaddr children, if not then we had better bail out1286if (isDirectJNI && unsafeCall->getChild(1)->getOpCodeValue() != TR::loadaddr)1287{1288traceMsg(comp(),"Unsafe Inlining: The Unsafe.monitorEnter/Exit() children are not loadaddr's as expected. Not inlining.\n");1289return unsafeCall;1290}12911292TR::Node::recreate(callNodeTreeTop->getNode(), TR::NULLCHK);1293callNodeTreeTop->getNode()->setSymbolReference(comp()->getSymRefTab()->findOrCreateNullCheckSymbolRef(comp()->getMethodSymbol()));12941295if (isEnter)1296{1297TR::Node::recreate(unsafeCall, TR::monent);1298TR::SymbolReference * monitorEnterSymbolRef = comp()->getSymRefTab()->findOrCreateMonitorEntrySymbolRef(comp()->getMethodSymbol());1299unsafeCall->setSymbolReference(monitorEnterSymbolRef);1300}1301else1302{1303TR::Node::recreate(unsafeCall, TR::monexit);1304TR::SymbolReference * monitorExitSymbolRef = comp()->getSymRefTab()->findOrCreateMonitorExitSymbolRef(comp()->getMethodSymbol());1305unsafeCall->setSymbolReference(monitorExitSymbolRef);1306}13071308TR::Node *oldChild = unsafeCall->getChild(0);1309// Anchor the unused oldChild1310callNodeTreeTop->insertBefore(TR::TreeTop::create(comp(), TR::Node::create(oldChild, TR::treetop, 1, oldChild)));1311if (isDirectJNI)1312{1313TR::Node::recreate(unsafeCall->getChild(1), TR::aload);1314}1315unsafeCall->setChild(0, unsafeCall->getChild(1));1316oldChild->recursivelyDecReferenceCount();1317unsafeCall->setChild(1, NULL);1318unsafeCall->setNumChildren(1);13191320if (!comp()->getOption(TR_DisableLiveMonitorMetadata))1321{1322TR::Node *storeNode = NULL;1323if (isEnter)1324{1325TR::SymbolReference * tempSymRef = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(), TR::Address);1326comp()->addAsMonitorAuto(tempSymRef, false);1327storeNode = TR::Node::createStore(tempSymRef, unsafeCall->getChild(0));1328}1329else1330{1331storeNode = TR::Node::create(unsafeCall,TR::monexitfence,0);1332}133313341335TR::TreeTop *storeTree = TR::TreeTop::create(comp(), storeNode);1336callNodeTreeTop->insertTreeTopsBeforeMe(storeTree);1337}13381339comp()->getMethodSymbol()->setMayContainMonitors(true);1340return unsafeCall;1341}13421343bool1344TR_J9InlinerPolicy::createUnsafeCASCallDiamond( TR::TreeTop *callNodeTreeTop, TR::Node *callNode)1345{1346// This method is used to create an if diamond around a call to any of the unsafe compare and swap methods1347// Codegens have a fast path for the compare and swaps, but cannot deal with the case where the offset value passed in to a the CAS is low tagged1348// (A low tagged offset value means the object being passed in is a java/lang/Class object, and we want a static field)13491350// This method assumes the offset node is of type long, and is the second child of the unsafe call.1351TR_InlinerDelimiter delimiter(tracer(),"createUnsafeCASCallDiamond");1352debugTrace(tracer(),"Transforming unsafe callNode = %p",callNode);13531354createTempsForUnsafeCall(callNodeTreeTop, callNode);13551356TR::Node *offsetNode = callNode->getChild(2);13571358TR::TreeTop *compareTree = genClassCheckForUnsafeGetPut(offsetNode);13591360// genClassCheck generates a ifcmpne offset&mask 1, meaning if it IS lowtagged (ie offset&mask == 1), the branch will be taken1361TR::TreeTop *ifTree = TR::TreeTop::create(comp(),callNodeTreeTop->getNode()->duplicateTree());1362ifTree->getNode()->getFirstChild()->setIsSafeForCGToFastPathUnsafeCall(true);136313641365TR::TreeTop *elseTree = TR::TreeTop::create(comp(),callNodeTreeTop->getNode()->duplicateTree());136613671368ifTree->getNode()->getFirstChild()->setVisitCount(_inliner->getVisitCount());1369elseTree->getNode()->getFirstChild()->setVisitCount(_inliner->getVisitCount());137013711372debugTrace(tracer(),"ifTree = %p elseTree = %p",ifTree->getNode(),elseTree->getNode());1373137413751376// the call itself may be commoned, so we need to create a temp for the callnode itself1377TR::SymbolReference *newSymbolReference = 0;1378TR::DataType dataType = callNode->getDataType();1379if(callNode->getReferenceCount() > 1)1380{1381newSymbolReference = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(), dataType);1382TR::Node::recreate(callNode, comp()->il.opCodeForDirectLoad(dataType));1383callNode->setSymbolReference(newSymbolReference);1384callNode->removeAllChildren();13851386debugTrace(tracer(),"Unsafe call has refcount > 1. Replacing callnode with a load of symref %d",newSymbolReference->getReferenceNumber());1387}13881389139013911392TR::Block *callBlock = callNodeTreeTop->getEnclosingBlock();13931394callBlock->createConditionalBlocksBeforeTree(callNodeTreeTop,compareTree, ifTree, elseTree, comp()->getFlowGraph(),false,false);13951396// the original call will be deleted by createConditionalBlocksBeforeTree, but if the refcount was > 1, we need to insert stores.13971398if (newSymbolReference)1399{1400TR::Node *ifStoreNode = TR::Node::createWithSymRef(comp()->il.opCodeForDirectStore(dataType), 1, 1, ifTree->getNode()->getFirstChild(), newSymbolReference);1401TR::TreeTop *ifStoreTree = TR::TreeTop::create(comp(), ifStoreNode);14021403ifTree->insertAfter(ifStoreTree);14041405debugTrace(tracer(),"Inserted store tree %p for if side of the diamond",ifStoreNode);14061407TR::Node *elseStoreNode = TR::Node::createWithSymRef(comp()->il.opCodeForDirectStore(dataType), 1, 1, elseTree->getNode()->getFirstChild(), newSymbolReference);1408TR::TreeTop *elseStoreTree = TR::TreeTop::create(comp(), elseStoreNode);14091410elseTree->insertAfter(elseStoreTree);14111412debugTrace(tracer(),"Inserted store tree %p for else side of the diamond",elseStoreNode);14131414}1415141614171418return true;1419}1420142114221423bool1424TR_J9InlinerPolicy::createUnsafeGetWithOffset(TR::ResolvedMethodSymbol *calleeSymbol, TR::ResolvedMethodSymbol *callerSymbol, TR::TreeTop * callNodeTreeTop, TR::Node * unsafeCall, TR::DataType type, bool isVolatile, bool needNullCheck)1425{1426if (isVolatile && type == TR::Int64 && comp()->target().is32Bit() && !comp()->cg()->getSupportsInlinedAtomicLongVolatiles())1427return false;14281429if (debug("traceUnsafe"))1430printf("createUnsafeGetWithOffset %s in %s\n", type.toString(), comp()->signature());14311432// Truncate the return before inlining the call1433if (TR_J9MethodBase::isUnsafeGetPutBoolean(calleeSymbol->getRecognizedMethod()))1434{1435TR::TransformUtil::truncateBooleanForUnsafeGetPut(comp(), callNodeTreeTop);1436}14371438// Preserve null check on the unsafe object1439TR::TransformUtil::separateNullCheck(comp(), callNodeTreeTop, tracer()->debugLevel());14401441TR::Node *unsafeAddress = unsafeCall->getChild(1);1442TR::Node *offset = unsafeCall->getChild(2);14431444TR::TreeTop *prevTreeTop = callNodeTreeTop->getPrevTreeTop();1445TR::SymbolReference *newSymbolReferenceForAddress = NULL;14461447// Since the block has to be split, we need to create temps for the arguments to the call1448// so that the right values are picked up in the 2 blocks that are targets of the if block1449// created for the inlining of the unsafe method1450//1451createTempsForUnsafePutGet(unsafeAddress, unsafeCall, callNodeTreeTop,1452offset, newSymbolReferenceForAddress, true);1453unsafeAddress = createUnsafeAddressWithOffset(unsafeCall);14541455for (int32_t j=0; j<unsafeCall->getNumChildren(); j++)1456unsafeCall->getChild(j)->recursivelyDecReferenceCount();1457unsafeCall->setNumChildren(1);14581459TR::SymbolReference* symRef = comp()->getSymRefTab()->findOrCreateUnsafeSymbolRef(type, true, false, isVolatile);1460bool conversionNeeded = comp()->fe()->dataTypeForLoadOrStore(type) != type;1461TR_ASSERT(unsafeCall == callNodeTreeTop->getNode()->getFirstChild(), "assumption not valid\n");1462TR::Node* unsafeCallWithConversion = NULL;1463TR::Node* callNodeWithConversion = NULL;1464if (conversionNeeded)1465{1466TR::Node* loadNode = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectArrayLoad(type),14671, 1, unsafeAddress, symRef);14681469bool unsignedType;14701471switch (calleeSymbol->getRecognizedMethod()) {1472//boolean and char are unsigned so we need an unsigned conversion1473case TR::sun_misc_Unsafe_getBoolean_jlObjectJ_Z:1474case TR::sun_misc_Unsafe_putBooleanVolatile_jlObjectJZ_V:1475case TR::sun_misc_Unsafe_getBooleanVolatile_jlObjectJ_Z:14761477case TR::sun_misc_Unsafe_getChar_jlObjectJ_C:1478case TR::sun_misc_Unsafe_getCharVolatile_jlObjectJ_C:1479case TR::sun_misc_Unsafe_getChar_J_C:1480unsignedType = true;1481break;1482//byte and short are signed so we need a signed conversion1483case TR::sun_misc_Unsafe_getByte_jlObjectJ_B:1484case TR::sun_misc_Unsafe_getByte_J_B:1485case TR::sun_misc_Unsafe_getByteVolatile_jlObjectJ_B:14861487case TR::sun_misc_Unsafe_getShort_jlObjectJ_S:1488case TR::sun_misc_Unsafe_getShortVolatile_jlObjectJ_S:1489case TR::sun_misc_Unsafe_getShort_J_S:1490unsignedType = false;1491break;1492default:1493TR_ASSERT(false, "all TR::sun_misc_Unsafe.get* methods must be handled.");1494}14951496TR::ILOpCodes conversionOpCode =1497TR::ILOpCode::getProperConversion(type,1498comp()->fe()->dataTypeForLoadOrStore(type),1499unsignedType);1500unsafeCallWithConversion = TR::Node::create(conversionOpCode, 1, loadNode);1501}15021503unsafeAddress->incReferenceCount();1504TR::Node::recreate(unsafeCall, comp()->il.opCodeForIndirectLoad(type));1505unsafeCall->setChild(0, unsafeAddress);1506unsafeCall->setSymbolReference(symRef);15071508TR::Node::recreate(callNodeTreeTop->getNode(), TR::treetop);1509TR::DataType dataType = unsafeCall->getDataType();1510TR::SymbolReference *newTemp = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(), dataType);1511TR::ILOpCodes storeOpCode = comp()->il.opCodeForDirectStore(unsafeCall->getDataType());1512TR::Node::recreate(callNodeTreeTop->getNode(), storeOpCode);1513callNodeTreeTop->getNode()->setSymbolReference(newTemp);15141515if (conversionNeeded)1516{1517callNodeWithConversion =1518TR::Node::createWithSymRef(storeOpCode, 1, 1, unsafeCallWithConversion, newTemp);1519}15201521TR::TreeTop* directAccessTreeTop =1522genDirectAccessCodeForUnsafeGetPut(callNodeTreeTop->getNode(), false, true);1523TR::TreeTop* arrayDirectAccessTreeTop = conversionNeeded1524? genDirectAccessCodeForUnsafeGetPut(callNodeWithConversion, conversionNeeded, true)1525: NULL;1526TR::TreeTop* indirectAccessTreeTop =1527genIndirectAccessCodeForUnsafeGetPut(callNodeTreeTop->getNode(), unsafeAddress);1528// If we are not able to get javaLangClass it is still inefficient to put direct Access far1529// So in that case we will generate lowTagCmpTest to branch to indirect access if true1530TR_OpaqueClassBlock *javaLangClass = comp()->fe()->getClassFromSignature("Ljava/lang/Class;",17, comp()->getCurrentMethod(),true);1531bool needNotLowTagged = javaLangClass != NULL || conversionNeeded ;1532// If we can get a J9Class or we need conversion we generate test to branch to direct access if low bit is not tagged1533// Else in case we get NULL instead of j9Class we generate test to branch to indirect access if low bit is tagged1534TR::TreeTop *lowTagCmpTree = genClassCheckForUnsafeGetPut(offset, needNotLowTagged);15351536TR::Block * joinBlock =1537addNullCheckForUnsafeGetPut(unsafeAddress, newSymbolReferenceForAddress,1538callNodeTreeTop, directAccessTreeTop,1539arrayDirectAccessTreeTop,1540indirectAccessTreeTop);15411542createAnchorNodesForUnsafeGetPut(directAccessTreeTop, type, true);1543if (arrayDirectAccessTreeTop)1544createAnchorNodesForUnsafeGetPut(arrayDirectAccessTreeTop, type, true);1545genCodeForUnsafeGetPut(unsafeAddress, callNodeTreeTop, prevTreeTop,1546newSymbolReferenceForAddress, directAccessTreeTop,1547lowTagCmpTree, needNullCheck, true, conversionNeeded,1548joinBlock, javaLangClass);15491550for (int32_t j=0; j<unsafeCall->getNumChildren(); j++)1551unsafeCall->getChild(j)->recursivelyDecReferenceCount();1552unsafeCall->setNumChildren(0);1553TR::Node::recreate(unsafeCall, comp()->il.opCodeForDirectLoad(unsafeCall->getDataType()));1554unsafeCall->setSymbolReference(newTemp);1555return true;15561557}15581559TR::Node *1560TR_J9InlinerPolicy::createUnsafeAddress(TR::Node * unsafeCall)1561{1562if (comp()->target().is64Bit())1563return unsafeCall->getChild(1); // should use l2a if we ever have one15641565return TR::Node::create(TR::l2i, 1, unsafeCall->getChild(1)); // should use i2a if we ever have one1566}15671568bool1569TR_J9InlinerPolicy::createUnsafePut(TR::ResolvedMethodSymbol *calleeSymbol, TR::ResolvedMethodSymbol *callerSymbol, TR::TreeTop * callNodeTreeTop, TR::Node * unsafeCall, TR::DataType type, bool compress)1570{1571if (debug("traceUnsafe"))1572printf("createUnsafePut %s in %s\n", type.toString(), comp()->signature());15731574// Preserve null check on the unsafe object1575TR::TransformUtil::separateNullCheck(comp(), callNodeTreeTop, tracer()->debugLevel());15761577TR::Node * address = createUnsafeAddress(unsafeCall);15781579TR::Node * value = unsafeCall->getChild(2);15801581TR::Node * unsafeNode;1582if (type == TR::Address)1583{1584if (comp()->target().is64Bit())1585{1586unsafeNode = TR::Node::createWithSymRef(TR::lstorei, 2, 2, address, value, comp()->getSymRefTab()->findOrCreateUnsafeSymbolRef(TR::Int64));1587}1588else1589{1590unsafeNode = TR::Node::create(TR::l2i, 1, value);1591unsafeNode = TR::Node::createWithSymRef(TR::istorei, 2, 2, address, unsafeNode, comp()->getSymRefTab()->findOrCreateUnsafeSymbolRef(TR::Int32));1592}1593}1594else1595{1596switch (type)1597{1598case TR::Int8:1599value = TR::Node::create(TR::i2b, 1, value);1600break;1601case TR::Int16:1602value = TR::Node::create(TR::i2s, 1, value);1603break;1604default:1605break;1606}1607unsafeNode = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectArrayStore(type), 2, 2, address, value, comp()->getSymRefTab()->findOrCreateUnsafeSymbolRef(type));1608}16091610if (compress && comp()->useCompressedPointers() &&1611(type == TR::Address))1612{1613unsafeNode = genCompressedRefs(unsafeNode, false, -1);1614}16151616callNodeTreeTop->setNode(unsafeNode);1617unsafeCall->recursivelyDecReferenceCount();16181619return true;16201621}16221623bool1624TR_J9InlinerPolicy::createUnsafeGet(TR::ResolvedMethodSymbol *calleeSymbol, TR::ResolvedMethodSymbol *callerSymbol, TR::TreeTop * callNodeTreeTop, TR::Node * unsafeCall, TR::DataType type, bool compress)1625{1626if (debug("traceUnsafe"))1627printf("createUnsafeGet %s in %s\n", type.toString(), comp()->signature());16281629// Preserve null check on the unsafe object1630TR::TransformUtil::separateNullCheck(comp(), callNodeTreeTop, tracer()->debugLevel());16311632TR::Node * unsafeAddress = createUnsafeAddress(unsafeCall);16331634TR::Node * unsafeNode;1635if (type == TR::Address)1636{1637if (comp()->target().is64Bit())1638{1639unsafeAddress->incReferenceCount();16401641int32_t j;1642for (j=0; j<unsafeCall->getNumChildren(); j++)1643unsafeCall->getChild(j)->recursivelyDecReferenceCount();16441645unsafeCall->setNumChildren(1);1646TR::Node::recreate(unsafeCall, TR::lloadi);1647unsafeCall->setSymbolReference(comp()->getSymRefTab()->findOrCreateUnsafeSymbolRef(TR::Int64));1648unsafeCall->setChild(0, unsafeAddress);1649unsafeNode = unsafeCall;1650}1651else1652{1653unsafeNode = TR::Node::createWithSymRef(TR::iloadi, 1, 1, unsafeAddress, comp()->getSymRefTab()->findOrCreateUnsafeSymbolRef(TR::Int32));16541655unsafeNode->incReferenceCount();16561657int32_t j;1658for (j=0; j<unsafeCall->getNumChildren(); j++)1659unsafeCall->getChild(j)->recursivelyDecReferenceCount();16601661unsafeCall->setNumChildren(1);1662TR::Node::recreate(unsafeCall, TR::iu2l);1663unsafeCall->setChild(0, unsafeNode);1664}1665}1666else1667{1668bool unsignedType = false;1669bool needConversion = false;1670switch (type)1671{1672case TR::Int8:1673case TR::Int16:1674needConversion = true;1675break;1676default:1677break;1678}16791680switch (calleeSymbol->getRecognizedMethod())1681{1682case TR::sun_misc_Unsafe_getChar_J_C:1683unsignedType = true;1684break;1685default:1686break;1687}16881689if (needConversion)1690unsafeNode = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectArrayLoad(type), 1, 1, unsafeAddress, comp()->getSymRefTab()->findOrCreateUnsafeSymbolRef(type));1691else1692unsafeNode = unsafeAddress;16931694unsafeNode->incReferenceCount();16951696int32_t j;1697for (j=0; j<unsafeCall->getNumChildren(); j++)1698unsafeCall->getChild(j)->recursivelyDecReferenceCount();16991700unsafeCall->setNumChildren(1);17011702switch (type)1703{1704case TR::Int8:1705TR::Node::recreate(unsafeCall, TR::b2i);1706break;1707case TR::Int16:1708if(unsignedType)1709TR::Node::recreate(unsafeCall, TR::su2i);1710else1711TR::Node::recreate(unsafeCall, TR::s2i);1712break;1713default:1714break;1715}17161717if (!needConversion)1718{1719TR::Node::recreate(unsafeCall, comp()->il.opCodeForIndirectArrayLoad(type));1720unsafeCall->setSymbolReference(comp()->getSymRefTab()->findOrCreateUnsafeSymbolRef(type));1721}17221723unsafeCall->setChild(0, unsafeNode);1724}17251726TR::TreeTop *compRefTT = NULL;1727if (compress && comp()->useCompressedPointers() &&1728(type == TR::Address))1729{1730// create the anchor node1731compRefTT = TR::TreeTop::create(comp(), genCompressedRefs(unsafeCall, false));1732}17331734if (compRefTT)1735{1736TR::TreeTop *prevTT = callNodeTreeTop->getPrevTreeTop();1737prevTT->join(compRefTT);1738}17391740TR::Node::recreate(callNodeTreeTop->getNode(), TR::treetop);17411742return true;17431744}17451746bool1747TR_J9InlinerPolicy::createUnsafeFence(TR::TreeTop *callNodeTreeTop, TR::Node *callNode, TR::ILOpCodes opCode)1748{1749TR::Node *fenceNode = TR::Node::createWithSymRef(callNode, opCode, 0, callNode->getSymbolReference());1750TR::Node::recreate(callNode, TR::PassThrough);1751TR::TreeTop *fenceTop = TR::TreeTop::create(comp(), fenceNode);1752callNodeTreeTop->insertAfter(fenceTop);1753return true;1754}17551756TR::Node *1757TR_J9InlinerPolicy::inlineGetClassAccessFlags(TR::ResolvedMethodSymbol *calleeSymbol, TR::ResolvedMethodSymbol *callerSymbol, TR::TreeTop * callNodeTreeTop, TR::Node * callNode)1758{1759if (1760comp()->getOption(TR_DisableInliningOfNatives) ||1761calleeSymbol->castToMethodSymbol()->getRecognizedMethod() != TR::sun_reflect_Reflection_getClassAccessFlags)1762return 0;17631764TR::Block * block = callNodeTreeTop->getEnclosingBlock();17651766TR::SymbolReference * modifiersSymRef = comp()->getSymRefTab()->createTemporary(callerSymbol, callNode->getDataType());17671768// generating "modifiers = J9VM_J9CLASS_FROM_HEAPCLASS(vmThread, *(j9object_t*)clazzRef)->romClass->modifiers;"17691770TR::Node *j9cNode;17711772if(callNode->isPreparedForDirectJNI())1773j9cNode = callNode->getSecondChild();1774else1775j9cNode = callNode->getFirstChild();17761777TR::Node::recreate(j9cNode, TR::aload);17781779j9cNode = TR::Node::createWithSymRef(TR::aloadi, 1, 1, j9cNode, comp()->getSymRefTab()->findOrCreateClassFromJavaLangClassSymbolRef());17801781TR::Node *nullCheckNode = TR::Node::createWithSymRef(TR::NULLCHK, 1, 1, j9cNode, comp()->getSymRefTab()->findOrCreateNullCheckSymbolRef(callerSymbol));1782TR::TreeTop *nullCheckTree = TR::TreeTop::create(comp(), nullCheckNode);1783TR::Node *romclassNode = TR::Node::createWithSymRef(TR::aloadi, 1, 1, j9cNode, comp()->getSymRefTab()->findOrCreateClassRomPtrSymbolRef());1784TR::Node *classAccessFlagsNode = TR::Node::createWithSymRef(TR::iloadi, 1, 1, romclassNode, comp()->getSymRefTab()->findOrCreateClassIsArraySymbolRef());1785TR::Node *modifiersNode = TR::Node::createStore(modifiersSymRef, classAccessFlagsNode);1786TR::TreeTop *modifiersTree = TR::TreeTop::create(comp(), modifiersNode);1787callNodeTreeTop->insertBefore(modifiersTree);1788modifiersTree->insertBefore(nullCheckTree);17891790/*** need to generate this:1791* if (modifiers & J9AccClassInternalPrimitiveType) {1792* modifiers = J9AccAbstract | J9AccFinal | J9AccPublic;1793* } else {1794* modifiers &= 0xFFF;1795* }1796* return modifiers;1797*/1798// generating "if (modifiers & J9AccClassInternalPrimitiveType)"1799TR::Node *iAndNode = TR::Node::create(TR::iand, 2,1800TR::Node::createLoad(callNode, modifiersSymRef),1801TR::Node::iconst(callNode, (int32_t)comp()->fej9()->constClassFlagsPrimitive()));1802TR::Node *compareNode = TR::Node::createif(TR::ificmpne,1803iAndNode,1804TR::Node::iconst(callNode, 0),18050);1806TR::TreeTop *compareTree = TR::TreeTop::create(comp(), compareNode);18071808// generating if-then part " modifiers = J9AccAbstract | J9AccFinal | J9AccPublic;"1809TR::Node *modifiersIfStrNode = TR::Node::createStore(modifiersSymRef,1810TR::Node::iconst(callNode, (int32_t)(comp()->fej9()->constClassFlagsAbstract() | comp()->fej9()->constClassFlagsFinal() | comp()->fej9()->constClassFlagsPublic()))1811);1812TR::TreeTop *ifTree = TR::TreeTop::create(comp(), modifiersIfStrNode);181318141815// generating else part " modifiers &= 0xFFF;"1816TR::Node *modifiersIAndNode = TR::Node::create(TR::iand, 2,1817TR::Node::createLoad(callNode, modifiersSymRef),1818TR::Node::iconst(callNode, 0xFFF));1819TR::Node *modifiersElseStrNode = TR::Node::createStore(modifiersSymRef, modifiersIAndNode);1820TR::TreeTop *elseTree = TR::TreeTop::create(comp(), modifiersElseStrNode);18211822// generating " return modifiers;"1823// - simply convert the original call node to an iload of the modifiers1824TR::Node *resultNode = callNode;1825TR::Node::recreate(callNode, TR::iload);1826callNode->removeAllChildren();1827callNode->setSymbolReference(modifiersSymRef);18281829block->createConditionalBlocksBeforeTree(callNodeTreeTop, compareTree, ifTree, elseTree, callerSymbol->getFlowGraph(), false);18301831return resultNode;18321833}18341835bool1836TR_J9InlinerPolicy::inlineUnsafeCall(TR::ResolvedMethodSymbol *calleeSymbol, TR::ResolvedMethodSymbol *callerSymbol, TR::TreeTop * callNodeTreeTop, TR::Node * callNode)1837{1838debugTrace(tracer(), "Unsafe Inlining: Trying to inline Unsafe Call at Node %p\n", callNode);18391840if (comp()->getOption(TR_DisableUnsafe))1841return false;18421843if (!callNode->getSymbol()->isResolvedMethod())1844return false;18451846if (comp()->fej9()->isAnyMethodTracingEnabled(calleeSymbol->getResolvedMethod()->getPersistentIdentifier()) &&1847!comp()->fej9()->traceableMethodsCanBeInlined())1848return false;18491850if ((TR::Compiler->vm.canAnyMethodEventsBeHooked(comp()) && !comp()->fej9()->methodsCanBeInlinedEvenIfEventHooksEnabled(comp())) ||1851(comp()->fej9()->isAnyMethodTracingEnabled(calleeSymbol->getResolvedMethod()->getPersistentIdentifier()) &&1852!comp()->fej9()->traceableMethodsCanBeInlined()))1853return false;18541855// I am not sure if having the same type between C/S and B/Z matters here.. ie. if the type is being used as the only distinguishing factor1856switch (callNode->getSymbol()->castToResolvedMethodSymbol()->getRecognizedMethod())1857{1858case TR::sun_misc_Unsafe_putByte_jlObjectJB_V:1859return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int8, false);1860case TR::sun_misc_Unsafe_putBoolean_jlObjectJZ_V:1861return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int8, false);1862case TR::sun_misc_Unsafe_putChar_jlObjectJC_V:1863return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16, false);1864case TR::sun_misc_Unsafe_putShort_jlObjectJS_V:1865return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16, false);1866case TR::sun_misc_Unsafe_putInt_jlObjectJI_V:1867return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int32, false);1868case TR::sun_misc_Unsafe_putLong_jlObjectJJ_V:1869return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int64, false);1870case TR::sun_misc_Unsafe_putFloat_jlObjectJF_V:1871return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Float, false);1872case TR::sun_misc_Unsafe_putDouble_jlObjectJD_V:1873return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Double, false);1874case TR::sun_misc_Unsafe_putObject_jlObjectJjlObject_V:1875return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Address, false, true);18761877case TR::sun_misc_Unsafe_getBoolean_jlObjectJ_Z:1878return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int8, false);1879case TR::sun_misc_Unsafe_getByte_jlObjectJ_B:1880return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int8, false);1881case TR::sun_misc_Unsafe_getChar_jlObjectJ_C:1882return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16, false);1883case TR::sun_misc_Unsafe_getShort_jlObjectJ_S:1884return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16, false);1885case TR::sun_misc_Unsafe_getInt_jlObjectJ_I:1886return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int32, false);1887case TR::sun_misc_Unsafe_getLong_jlObjectJ_J:1888return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int64, false);1889case TR::sun_misc_Unsafe_getFloat_jlObjectJ_F:1890return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Float, false);1891case TR::sun_misc_Unsafe_getDouble_jlObjectJ_D:1892return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Double, false);1893case TR::sun_misc_Unsafe_getObject_jlObjectJ_jlObject:1894return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Address, false, true);18951896case TR::sun_misc_Unsafe_putByteVolatile_jlObjectJB_V:1897return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int8, true);1898case TR::sun_misc_Unsafe_putBooleanVolatile_jlObjectJZ_V:1899return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int8, true);1900case TR::sun_misc_Unsafe_putCharVolatile_jlObjectJC_V:1901return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16, true);1902case TR::sun_misc_Unsafe_putShortVolatile_jlObjectJS_V:1903return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16, true);1904case TR::sun_misc_Unsafe_putIntVolatile_jlObjectJI_V:1905return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int32, true);1906case TR::sun_misc_Unsafe_putLongVolatile_jlObjectJJ_V:1907return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int64, true);1908case TR::sun_misc_Unsafe_putFloatVolatile_jlObjectJF_V:1909return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Float, true);1910case TR::sun_misc_Unsafe_putDoubleVolatile_jlObjectJD_V:1911return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Double, true);1912case TR::sun_misc_Unsafe_putObjectVolatile_jlObjectJjlObject_V:1913return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Address, true, true);19141915case TR::sun_misc_Unsafe_monitorEnter_jlObject_V:1916return createUnsafeMonitorOp(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, true);1917case TR::sun_misc_Unsafe_monitorExit_jlObject_V:1918return createUnsafeMonitorOp(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, false);19191920case TR::sun_misc_Unsafe_putByteOrdered_jlObjectJB_V:1921return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int8, false, false, true);1922case TR::sun_misc_Unsafe_putBooleanOrdered_jlObjectJZ_V:1923return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int8, false, false, true);1924case TR::sun_misc_Unsafe_putCharOrdered_jlObjectJC_V:1925return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16, false, false, true);1926case TR::sun_misc_Unsafe_putShortOrdered_jlObjectJS_V:1927return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16, false, false, true);1928case TR::sun_misc_Unsafe_putIntOrdered_jlObjectJI_V:1929return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int32, false, false, true);1930case TR::sun_misc_Unsafe_putLongOrdered_jlObjectJJ_V:1931return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int64, false, false, true);1932case TR::sun_misc_Unsafe_putFloatOrdered_jlObjectJF_V:1933return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Float, false, false, true);1934case TR::sun_misc_Unsafe_putDoubleOrdered_jlObjectJD_V:1935return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Double, false, false, true);1936case TR::sun_misc_Unsafe_putObjectOrdered_jlObjectJjlObject_V:1937return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Address, false, true, true);19381939case TR::sun_misc_Unsafe_getBooleanVolatile_jlObjectJ_Z:1940return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int8, true);1941case TR::sun_misc_Unsafe_getByteVolatile_jlObjectJ_B:1942return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int8, true);1943case TR::sun_misc_Unsafe_getCharVolatile_jlObjectJ_C:1944return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16, true);1945case TR::sun_misc_Unsafe_getShortVolatile_jlObjectJ_S:1946return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16, true);1947case TR::sun_misc_Unsafe_getIntVolatile_jlObjectJ_I:1948return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int32, true);1949case TR::sun_misc_Unsafe_getLongVolatile_jlObjectJ_J:1950return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int64, true);1951case TR::sun_misc_Unsafe_getFloatVolatile_jlObjectJ_F:1952return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Float, true);1953case TR::sun_misc_Unsafe_getDoubleVolatile_jlObjectJ_D:1954return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Double, true);1955case TR::sun_misc_Unsafe_getObjectVolatile_jlObjectJ_jlObject:1956return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Address, true, true);19571958case TR::sun_misc_Unsafe_putByte_JB_V:1959case TR::org_apache_harmony_luni_platform_OSMemory_putByte_JB_V:1960return createUnsafePut(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int8);1961case TR::sun_misc_Unsafe_putChar_JC_V:1962return createUnsafePut(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16);1963case TR::sun_misc_Unsafe_putShort_JS_V:1964case TR::org_apache_harmony_luni_platform_OSMemory_putShort_JS_V:1965return createUnsafePut(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16);1966case TR::sun_misc_Unsafe_putInt_JI_V:1967case TR::org_apache_harmony_luni_platform_OSMemory_putInt_JI_V:1968return createUnsafePut(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int32);1969case TR::sun_misc_Unsafe_putLong_JJ_V:1970case TR::org_apache_harmony_luni_platform_OSMemory_putLong_JJ_V:1971return createUnsafePut(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int64);1972case TR::sun_misc_Unsafe_putFloat_JF_V:1973case TR::org_apache_harmony_luni_platform_OSMemory_putFloat_JF_V:1974return createUnsafePut(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Float);1975case TR::sun_misc_Unsafe_putDouble_JD_V:1976case TR::org_apache_harmony_luni_platform_OSMemory_putDouble_JD_V:1977return createUnsafePut(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Double);1978case TR::sun_misc_Unsafe_putAddress_JJ_V:1979case TR::org_apache_harmony_luni_platform_OSMemory_putAddress_JJ_V:1980return createUnsafePut(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Address, false);19811982case TR::sun_misc_Unsafe_getByte_J_B:1983case TR::org_apache_harmony_luni_platform_OSMemory_getByte_J_B:1984return createUnsafeGet(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int8);1985case TR::sun_misc_Unsafe_getChar_J_C:1986return createUnsafeGet(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16);1987case TR::sun_misc_Unsafe_getShort_J_S:1988case TR::org_apache_harmony_luni_platform_OSMemory_getShort_J_S:1989return createUnsafeGet(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16);1990case TR::sun_misc_Unsafe_getInt_J_I:1991case TR::org_apache_harmony_luni_platform_OSMemory_getInt_J_I:1992return createUnsafeGet(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int32);1993case TR::sun_misc_Unsafe_getLong_J_J:1994case TR::org_apache_harmony_luni_platform_OSMemory_getLong_J_J:1995return createUnsafeGet(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int64);1996case TR::sun_misc_Unsafe_getFloat_J_F:1997case TR::org_apache_harmony_luni_platform_OSMemory_getFloat_J_F:1998return createUnsafeGet(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Float);1999case TR::sun_misc_Unsafe_getDouble_J_D:2000case TR::org_apache_harmony_luni_platform_OSMemory_getDouble_J_D:2001return createUnsafeGet(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Double);2002case TR::sun_misc_Unsafe_getAddress_J_J:2003case TR::org_apache_harmony_luni_platform_OSMemory_getAddress_J_J:2004return createUnsafeGet(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Address, false);20052006case TR::sun_misc_Unsafe_loadFence:2007return createUnsafeFence(callNodeTreeTop, callNode, TR::loadFence);2008case TR::sun_misc_Unsafe_storeFence:2009return createUnsafeFence(callNodeTreeTop, callNode, TR::storeFence);2010case TR::sun_misc_Unsafe_fullFence:2011return createUnsafeFence(callNodeTreeTop, callNode, TR::fullFence);20122013case TR::sun_misc_Unsafe_staticFieldBase:2014return false; // todo2015case TR::sun_misc_Unsafe_staticFieldOffset:2016return false; // todo2017case TR::sun_misc_Unsafe_objectFieldOffset:2018return false; // todo20192020case TR::sun_misc_Unsafe_compareAndSwapInt_jlObjectJII_Z:2021case TR::sun_misc_Unsafe_compareAndSwapLong_jlObjectJJJ_Z:2022case TR::sun_misc_Unsafe_compareAndSwapObject_jlObjectJjlObjectjlObject_Z:2023if (callNode->isSafeForCGToFastPathUnsafeCall())2024return false;2025switch (callerSymbol->castToMethodSymbol()->getRecognizedMethod())2026{2027case TR::java_util_concurrent_ConcurrentHashMap_addCount:2028case TR::java_util_concurrent_ConcurrentHashMap_casTabAt:2029case TR::java_util_concurrent_ConcurrentHashMap_fullAddCount:2030case TR::java_util_concurrent_ConcurrentHashMap_helpTransfer:2031case TR::java_util_concurrent_ConcurrentHashMap_initTable:2032case TR::java_util_concurrent_ConcurrentHashMap_transfer:2033case TR::java_util_concurrent_ConcurrentHashMap_tryPresize:2034case TR::java_util_concurrent_ConcurrentHashMap_TreeBin_contendedLock:2035case TR::java_util_concurrent_ConcurrentHashMap_TreeBin_find:2036case TR::java_util_concurrent_ConcurrentHashMap_TreeBin_lockRoot:2037case TR::com_ibm_jit_JITHelpers_compareAndSwapIntInObject:2038case TR::com_ibm_jit_JITHelpers_compareAndSwapLongInObject:2039case TR::com_ibm_jit_JITHelpers_compareAndSwapObjectInObject:2040case TR::com_ibm_jit_JITHelpers_compareAndSwapIntInArray:2041case TR::com_ibm_jit_JITHelpers_compareAndSwapLongInArray:2042case TR::com_ibm_jit_JITHelpers_compareAndSwapObjectInArray:2043callNode->setIsSafeForCGToFastPathUnsafeCall(true);2044return callNode;2045default:2046return createUnsafeCASCallDiamond(callNodeTreeTop, callNode);2047}2048default:2049break;2050}20512052return false;2053}205420552056bool2057TR_J9InlinerPolicy::isInlineableJNI(TR_ResolvedMethod *method,TR::Node *callNode)2058{2059TR::Compilation* comp = TR::comp();2060TR::RecognizedMethod recognizedMethod = method->getRecognizedMethod();2061// Reflection's JNI2062//2063if (!comp->getOption(TR_DisableInliningOfNatives) &&2064recognizedMethod == TR::sun_reflect_Reflection_getClassAccessFlags)2065//return false;2066return true;20672068// Unsafe's JNIs2069//2070if (comp->getOption(TR_DisableUnsafe))2071return false;20722073// If this put ordered call node has already been inlined, do not inline it again (JTC-JAT 71313)2074if (callNode && callNode->isUnsafePutOrderedCall() && callNode->isDontInlinePutOrderedCall())2075{2076debugTrace(tracer(), "Unsafe Inlining: Unsafe Call %p already inlined\n", callNode);20772078return false;2079}20802081if ((TR::Compiler->vm.canAnyMethodEventsBeHooked(comp) && !comp->fej9()->methodsCanBeInlinedEvenIfEventHooksEnabled(comp)) ||2082(comp->fej9()->isAnyMethodTracingEnabled(method->getPersistentIdentifier()) &&2083!comp->fej9()->traceableMethodsCanBeInlined()))2084return false;20852086if (method->convertToMethod()->isUnsafeWithObjectArg(comp) || method->convertToMethod()->isUnsafeCAS(comp))2087{2088// In Java9 sun/misc/Unsafe methods are simple Java wrappers to JNI2089// methods in jdk.internal, and the enum values above match both. Only2090// return true for the methods that are native.2091if (!TR::Compiler->om.canGenerateArraylets() || (callNode && callNode->isUnsafeGetPutCASCallOnNonArray()))2092return method->isNative();2093else2094return false;2095}20962097switch (recognizedMethod)2098{20992100case TR::sun_misc_Unsafe_monitorEnter_jlObject_V:2101case TR::sun_misc_Unsafe_monitorExit_jlObject_V:21022103case TR::sun_misc_Unsafe_putByte_JB_V:2104case TR::org_apache_harmony_luni_platform_OSMemory_putByte_JB_V:2105case TR::sun_misc_Unsafe_putChar_JC_V:2106case TR::sun_misc_Unsafe_putShort_JS_V:2107case TR::org_apache_harmony_luni_platform_OSMemory_putShort_JS_V:2108case TR::sun_misc_Unsafe_putInt_JI_V:2109case TR::org_apache_harmony_luni_platform_OSMemory_putInt_JI_V:2110case TR::sun_misc_Unsafe_putLong_JJ_V:2111case TR::org_apache_harmony_luni_platform_OSMemory_putLong_JJ_V:2112case TR::sun_misc_Unsafe_putFloat_JF_V:2113case TR::org_apache_harmony_luni_platform_OSMemory_putFloat_JF_V:2114case TR::sun_misc_Unsafe_putDouble_JD_V:2115case TR::org_apache_harmony_luni_platform_OSMemory_putDouble_JD_V:2116case TR::sun_misc_Unsafe_putAddress_JJ_V:2117case TR::org_apache_harmony_luni_platform_OSMemory_putAddress_JJ_V:21182119case TR::sun_misc_Unsafe_getByte_J_B:2120case TR::org_apache_harmony_luni_platform_OSMemory_getByte_J_B:2121case TR::sun_misc_Unsafe_getChar_J_C:2122case TR::sun_misc_Unsafe_getShort_J_S:2123case TR::org_apache_harmony_luni_platform_OSMemory_getShort_J_S:2124case TR::sun_misc_Unsafe_getInt_J_I:2125case TR::org_apache_harmony_luni_platform_OSMemory_getInt_J_I:2126case TR::sun_misc_Unsafe_getLong_J_J:2127case TR::org_apache_harmony_luni_platform_OSMemory_getLong_J_J:2128case TR::sun_misc_Unsafe_getFloat_J_F:2129case TR::org_apache_harmony_luni_platform_OSMemory_getFloat_J_F:2130case TR::sun_misc_Unsafe_getDouble_J_D:2131case TR::org_apache_harmony_luni_platform_OSMemory_getDouble_J_D:2132case TR::sun_misc_Unsafe_getAddress_J_J:2133case TR::org_apache_harmony_luni_platform_OSMemory_getAddress_J_J:21342135case TR::sun_misc_Unsafe_loadFence:2136case TR::sun_misc_Unsafe_storeFence:2137case TR::sun_misc_Unsafe_fullFence:2138return true;21392140case TR::sun_misc_Unsafe_staticFieldBase:2141return false; // todo2142case TR::sun_misc_Unsafe_staticFieldOffset:2143return false; // todo2144case TR::sun_misc_Unsafe_objectFieldOffset:2145return false; // todo21462147default:2148break;2149}21502151return false;2152}21532154//first check J9 specific tryToInline methods and then general tryToInline methods2155bool2156TR_J9InlinerPolicy::tryToInline(TR_CallTarget * calltarget, TR_CallStack * callStack, bool toInline)2157{2158TR_ResolvedMethod *method = calltarget->_calleeMethod;21592160if (toInline && insideIntPipelineForEach(method, comp()))2161{2162if (comp()->trace(OMR::inlining))2163traceMsg(comp(), "forcing inlining of IntPipelineForEach or method inside it: %s\n", method->signature(comp()->trMemory()));21642165return true;2166}21672168if (toInline)2169{2170if (!comp()->getOption(TR_DisableForceInlineAnnotations) &&2171comp()->fej9()->isForceInline(method))2172{2173if (comp()->trace(OMR::inlining))2174traceMsg(comp(), "@ForceInline was specified for %s, in tryToInline\n", method->signature(comp()->trMemory()));2175return true;2176}2177}21782179if (OMR_InlinerPolicy::tryToInlineGeneral(calltarget, callStack, toInline))2180return true;21812182return false;2183}21842185bool2186TR_J9InlinerPolicy::inlineMethodEvenForColdBlocks(TR_ResolvedMethod *method)2187{2188bool insideForEach = insideIntPipelineForEach(method, comp());2189return insideForEach;2190}21912192void2193TR_J9InlinerPolicy::adjustFanInSizeInWeighCallSite(int32_t& weight,2194int32_t size,2195TR_ResolvedMethod* callee,2196TR_ResolvedMethod* caller,2197int32_t bcIndex)2198{2199/*2200Our goal is to use the ratio of the weight of a particular caller to the total weight to penalize the callers whose weights are relatively small.2201To reach that goal, we have to introduce two magic numbers: defaultWeight and TR::Options::INLINE_fanInCallGraphFactor.2202*defaultWeight is used when our caller belongs in the other bucket, so we don't have a meaningful weight to represent it.2203*INLINE_fanInCallGraphFactor is simply hand-tuned number by which we multiply our ratio.22042205INLINE_fanInCallGraphFactor is an integer number divided by 100. This allows us to avoid using float numbers for specifying the factor.2206*/2207220822092210if (comp()->getMethodHotness() > warm)2211return;22122213static const char *qq = feGetEnv("TR_Min_FanIn_Size");2214static const uint32_t min_size = ( qq ) ? atoi(qq) : MIN_FAN_IN_SIZE;22152216uint32_t thresholdSize = (!comp()->getOption(TR_InlinerFanInUseCalculatedSize)) ? getJ9InitialBytecodeSize(callee, 0, comp()) : size;2217if (thresholdSize <= min_size) // if we are less than min_fan_in size, we don't want to apply fan-in heuristic2218{2219return;2220}22212222static const char *qqq = feGetEnv("TR_OtherBucketThreshold");2223static const float otherBucketThreshold = (qqq) ? (float) (atoi (qqq) /100.0) : FANIN_OTHER_BUCKET_THRESHOLD ;22242225//convenience2226TR_ResolvedJ9Method *resolvedJ9Callee = (TR_ResolvedJ9Method *) callee;2227TR_ResolvedJ9Method *resolvedJ9Caller = (TR_ResolvedJ9Method *) caller;222822292230uint32_t numCallers = 0, totalWeight = 0, fanInWeight = 0, otherBucketWeight = 0;2231resolvedJ9Callee->getFaninInfo(&numCallers, &totalWeight, &otherBucketWeight);22322233if (numCallers < MIN_NUM_CALLERS || (totalWeight > 0 && otherBucketWeight * 1.0 / totalWeight < otherBucketThreshold))2234return;22352236bool hasCaller = resolvedJ9Callee->getCallerWeight(resolvedJ9Caller, &fanInWeight, bcIndex);22372238if (size >= 0 && totalWeight && fanInWeight)2239{2240static const char *q4 = feGetEnv("TR_MagicNumber");2241static const int32_t magicNumber = q4 ? atoi (q4) : 1 ;22422243float dynamicFanInRatio = hasCaller ? ((float)totalWeight - (float)fanInWeight) / (float) totalWeight : (float) fanInWeight / (float) totalWeight;22442245int32_t oldWeight = weight;2246weight += weight*dynamicFanInRatio*magicNumber;22472248heuristicTrace (tracer(), "FANIN: callee %s in caller %s @ %d oldWeight %d weight %d",2249callee->signature(comp()->trMemory()),2250caller->signature(comp()->trMemory()),2251bcIndex, oldWeight, weight2252);22532254}2255}22562257bool TR_J9InlinerPolicy::_tryToGenerateILForMethod (TR::ResolvedMethodSymbol* calleeSymbol, TR::ResolvedMethodSymbol* callerSymbol, TR_CallTarget* calltarget)2258{2259bool success = false;2260TR::Node * callNode = calltarget->_myCallSite->_callNode;22612262TR::IlGeneratorMethodDetails storage;2263TR::IlGeneratorMethodDetails & ilGenMethodDetails = TR::IlGeneratorMethodDetails::create(storage, calleeSymbol->getResolvedMethod());2264if (!comp()->getOption(TR_DisablePartialInlining) && calltarget->_partialInline)2265{2266heuristicTrace(tracer(),"Doing a partialInline for method %s\n",tracer()->traceSignature(calleeSymbol));2267TR::PartialInliningIlGenRequest ilGenRequest(ilGenMethodDetails, callerSymbol, calltarget->_partialInline);22682269if (comp()->trace(OMR::inlining))2270{2271traceMsg(comp(), "ILGen of [%p] using request: ", callNode);2272ilGenRequest.print(comp()->fe(), comp()->getOutFile(), "\n");2273}2274success = calleeSymbol->genIL(comp()->fe(), comp(), comp()->getSymRefTab(), ilGenRequest);2275}2276else2277{2278TR::InliningIlGenRequest ilGenRequest(ilGenMethodDetails, callerSymbol);2279if (comp()->trace(OMR::inlining))2280{2281ilGenRequest.print(comp()->fe(), comp()->getOutFile(), "\n");2282}2283success = calleeSymbol->genIL(comp()->fe(), comp(), comp()->getSymRefTab(), ilGenRequest);2284}22852286return success;2287}22882289bool TR_J9InlinerPolicy::tryToInlineTrivialMethod (TR_CallStack* callStack, TR_CallTarget* calltarget)2290{2291TR::Node * callNode = calltarget->_myCallSite->_callNode;2292TR::ResolvedMethodSymbol * calleeSymbol = calltarget->_calleeSymbol;2293TR::TreeTop * callNodeTreeTop = calltarget->_myCallSite->_callNodeTreeTop;2294TR_VirtualGuardSelection *guard = calltarget->_guard;2295TR::ResolvedMethodSymbol * callerSymbol = callStack->_methodSymbol;22962297if (isInlineableJNI(calleeSymbol->getResolvedMethod(),callNode))2298{2299if (performTransformation(comp(), "%sInlining jni %s into %s\n", OPT_DETAILS, calleeSymbol->signature(comp()->trMemory()), callerSymbol->signature(comp()->trMemory())))2300{2301if (calltarget->_myCallSite->isIndirectCall())2302return true;23032304if (inlineGetClassAccessFlags(calleeSymbol, callerSymbol, callNodeTreeTop, callNode))2305guard->_kind = TR_NoGuard;2306else if (inlineUnsafeCall(calleeSymbol, callerSymbol, callNodeTreeTop, callNode))2307guard->_kind = TR_NoGuard;2308}2309return true;2310}23112312return false;2313}23142315bool2316TR_J9InlinerPolicy::adjustFanInSizeInExceedsSizeThreshold(int bytecodeSize,2317uint32_t& calculatedSize,2318TR_ResolvedMethod* callee,2319TR_ResolvedMethod* caller,2320int32_t bcIndex)2321{2322if (comp()->getMethodHotness() > warm)2323return false;23242325static const char *q = feGetEnv("TR_SizeMultiplier");2326static const uint32_t multiplier = ( q ) ? atoi (q) : SIZE_MULTIPLIER;23272328static const char *qq = feGetEnv("TR_Min_FanIn_Size");2329static const uint32_t min_size = ( qq ) ? atoi(qq) : MIN_FAN_IN_SIZE;23302331static const char *qqq = feGetEnv("TR_OtherBucketThreshold");2332static const float otherBucketThreshold = (qqq) ? (float) (atoi (qqq) /100.0) : FANIN_OTHER_BUCKET_THRESHOLD;233323342335uint32_t thresholdSize = (!comp()->getOption(TR_InlinerFanInUseCalculatedSize)) ? getJ9InitialBytecodeSize(callee, 0, comp()) : calculatedSize;2336if (thresholdSize <= min_size) // if we are less than min_fan_in size, we don't want to apply fan-in heuristic2337{2338return false;2339}23402341TR_ResolvedJ9Method *resolvedJ9Callee = (TR_ResolvedJ9Method *) callee;2342TR_ResolvedJ9Method *resolvedJ9Caller = (TR_ResolvedJ9Method *) caller;23432344uint32_t numCallers = 0, totalWeight = 0, otherBucketWeight = 0;2345float dynamicFanInRatio = 0.0;2346resolvedJ9Callee->getFaninInfo(&numCallers, &totalWeight, &otherBucketWeight);23472348if (numCallers < MIN_NUM_CALLERS || (totalWeight > 0 && otherBucketWeight * 1.0 / totalWeight < otherBucketThreshold))2349return false;2350235123522353uint32_t weight = 0;2354bool hasCaller = resolvedJ9Callee->getCallerWeight(resolvedJ9Caller, &weight, bcIndex);23552356/*2357* We assume that if the caller lands in the other bucket it is not worth trouble inlining2358* There seem to be an empirical evidence to that.2359* If we increase the number of callers we remember up to 402360* Still a considerable share of calls lands in the other bucket2361* This indirectly suggests that the other bucket typically consists of2362* a lot of infrequent caller-bcIndex pairs2363*/23642365if (!hasCaller && weight != ~0) //the caller is in the other bucket2366{2367heuristicTrace (tracer(), "FANIN: callee %s in caller %s @ %d exceeds thresholds due to the caller being in the other bucket",2368callee->signature(comp()->trMemory()),2369caller->signature(comp()->trMemory()),2370bcIndex2371);23722373return true;2374}23752376if (weight != ~0) //there is an entry for this particular caller2377dynamicFanInRatio = (float)weight / (float)totalWeight ;23782379int32_t oldCalculatedSize = calculatedSize;2380if (dynamicFanInRatio == 0.0)2381calculatedSize = bytecodeSize * multiplier; //weight == ~0 we don't know anything about the caller2382else2383calculatedSize = (uint32_t) ((float)bytecodeSize/dynamicFanInRatio);23842385heuristicTrace (tracer(), "FANIN: callee %s in caller %s @ %d oldCalculatedSize %d calculatedSize %d",2386callee->signature(comp()->trMemory()),2387caller->signature(comp()->trMemory()),2388bcIndex, oldCalculatedSize, calculatedSize2389);23902391return false;2392}23932394bool2395TR_J9InlinerPolicy::callMustBeInlined(TR_CallTarget *calltarget)2396{2397TR_ResolvedMethod *method = calltarget->_calleeMethod;23982399if (method->convertToMethod()->isArchetypeSpecimen())2400return true;24012402if (comp()->fej9()->isLambdaFormGeneratedMethod(method))2403return true;24042405if (insideIntPipelineForEach(method, comp()))2406{2407if (comp()->trace(OMR::inlining))2408traceMsg(comp(), "forcing inlining of IntPipelineForEach or method inside it: %s\n", method->signature(comp()->trMemory()));24092410return true;2411}241224132414if (comp()->getOption(TR_EnableSIMDLibrary) &&2415strncmp(calltarget->_calleeMethod->classNameChars(), "com/ibm/dataaccess/SIMD", 23) == 0)2416return true;24172418#ifdef ENABLE_GPU2419if (strncmp(calltarget->_calleeMethod->classNameChars(), "com/ibm/gpu/Kernel", 18) == 0)2420return true;2421#endif242224232424if (!comp()->getOption(TR_DisableForceInlineAnnotations) &&2425comp()->fej9()->isForceInline(method))2426{2427int32_t length = method->classNameLength();2428char* className = method->classNameChars();24292430bool vectorMethod = false;2431if (length >= 23 && !strncmp(className, "jdk/internal/vm/vector/", 23))2432vectorMethod = true;2433if (length >= 21 && !strncmp(className, "jdk/incubator/vector/", 21))2434vectorMethod = true;24352436if (vectorMethod)2437{2438if (comp()->trace(OMR::inlining))2439traceMsg(comp(), "@ForceInline was specified for %s, in callMustBeInlined\n", method->signature(comp()->trMemory()));2440return true;2441}2442}24432444return false;2445}24462447void2448TR_J9InlinerUtil::adjustCallerWeightLimit(TR::ResolvedMethodSymbol *callerSymbol, int &callerWeightLimit)2449{2450if (inliner()->getPolicy()->aggressiveSmallAppOpts() && (callerSymbol->getRecognizedMethod() == TR::java_util_GregorianCalendar_computeFields) && isHot(comp()))2451callerWeightLimit = 2600;2452}245324542455void2456TR_J9InlinerUtil::adjustMethodByteCodeSizeThreshold(TR::ResolvedMethodSymbol *callerSymbol, int &methodByteCodeSizeThreshold)2457{2458if (inliner()->getPolicy()->aggressiveSmallAppOpts() && (callerSymbol->getRecognizedMethod() == TR::java_util_GregorianCalendar_computeFields))2459methodByteCodeSizeThreshold = 400;2460}246124622463bool2464TR_J9InlinerPolicy::willBeInlinedInCodeGen(TR::RecognizedMethod method)2465{2466#ifdef J9VM_OPT_JAVA_CRYPTO_ACCELERATION2467if (willInlineCryptoMethodInCodeGen(method))2468{2469return true;2470}2471#endif24722473return false;2474}24752476bool2477TR_J9InlinerPolicy::skipHCRGuardForCallee(TR_ResolvedMethod *callee)2478{2479// TODO: This is a very hacky way of avoiding HCR guards on sensitive String Compression methods which allows idiom2480// recognition to work. It also avoids unnecessary block splitting in performance sensitive methods for String2481// operations that are quite common. Can we do something better?2482TR::RecognizedMethod rm = callee->getRecognizedMethod();2483switch (rm)2484{2485case TR::java_lang_String_charAtInternal_I:2486case TR::java_lang_String_charAtInternal_IB:2487case TR::java_lang_String_lengthInternal:2488case TR::java_lang_String_isCompressed:2489case TR::java_lang_StringUTF16_length:2490case TR::java_lang_StringBuffer_capacityInternal:2491case TR::java_lang_StringBuffer_lengthInternalUnsynchronized:2492case TR::java_lang_StringBuilder_capacityInternal:2493case TR::java_lang_StringBuilder_lengthInternal:2494return true;2495default:2496break;2497}24982499// VectorSupport intrinsic candidates should not be redefined by the user2500if (rm >= TR::FirstVectorMethod &&2501rm <= TR::LastVectorIntrinsicMethod)2502return true;25032504// Skip HCR guard for non-public methods in java/lang/invoke package. These methods2505// are related to implementation details of MethodHandle and VarHandle2506int32_t length = callee->classNameLength();2507char* className = callee->classNameChars();2508if (length > 172509&& !strncmp("java/lang/invoke/", className, 17)2510&& !callee->isPublic())2511return true;25122513return false;2514}25152516TR_J9InlinerPolicy::TR_J9InlinerPolicy(TR::Compilation *comp)2517: _aggressivelyInlineInLoops(false), OMR_InlinerPolicy(comp)2518{25192520}25212522TR_J9JSR292InlinerPolicy::TR_J9JSR292InlinerPolicy(TR::Compilation *comp)2523: TR_J9InlinerPolicy(comp)2524{25252526}25272528TR_J9InlinerUtil::TR_J9InlinerUtil(TR::Compilation *comp)2529: OMR_InlinerUtil(comp)2530{25312532}25332534TR_Inliner::TR_Inliner(TR::OptimizationManager *manager)2535: TR::Optimization(manager)2536{}25372538int32_t TR_Inliner::perform()2539{2540//static bool enableInliningInOSR = feGetEnv("TR_disableInliningInOSR") != NULL;25412542//Disabled, but putting in here an env option to enable it for testing2543//this is not the best spot but the other didn't work out2544//and it's temporary anyways2545static const char* enableMT4Testing = feGetEnv("TR_EnableMT4Testing");25462547if (!enableMT4Testing)2548comp()->setOption(TR_DisableMultiTargetInlining);254925502551TR::ResolvedMethodSymbol * sym = comp()->getMethodSymbol();2552if (sym->mayHaveInlineableCall() && optimizer()->isEnabled(OMR::inlining))2553{2554comp()->getFlowGraph()->setStructure(NULL);25552556TR_MultipleCallTargetInliner inliner(optimizer(),this);2557if (manager()->numPassesCompleted() == 0)2558inliner.setFirstPass();2559inliner.performInlining(sym);2560manager()->incNumPassesCompleted();2561comp()->getFlowGraph()->resetFrequencies();2562comp()->getFlowGraph()->setFrequencies();2563}25642565// this should run after all inlining is done in order not to2566// miss any VectorAPI methods2567if (TR_VectorAPIExpansion::findVectorMethods(comp()))2568comp()->getMethodSymbol()->setHasVectorAPI(true);25692570return 1; // cost??2571}25722573const char *2574TR_Inliner::optDetailString() const throw()2575{2576return "O^O INLINER: ";2577}25782579template <typename FunctObj>2580void TR_MultipleCallTargetInliner::recursivelyWalkCallTargetAndPerformAction(TR_CallTarget *ct, FunctObj &action)2581{25822583debugTrace(tracer(),"recursivelyWalkingCallTargetAndPerformAction: Considering Target %p. node estimate before = %d maxbcindex = %d",ct,action.getNodeEstimate(),getPolicy()->getInitialBytecodeSize(ct->_calleeMethod, 0, comp()));25842585action(ct,comp());25862587TR_CallSite *callsite = 0;2588for(callsite = ct->_myCallees.getFirst() ; callsite ; callsite = callsite->getNext() )2589{2590for (int32_t i = 0 ; i < callsite->numTargets() ; i++)2591{2592recursivelyWalkCallTargetAndPerformAction(callsite->getTarget(i),action);2593}2594}259525962597}25982599int32_t2600TR_MultipleCallTargetInliner::applyArgumentHeuristics(TR_LinkHead<TR_ParameterMapping> &map, int32_t originalWeight, TR_CallTarget *target)2601{2602int32_t weight = originalWeight;2603TR_PrexArgInfo *argInfo = target->_ecsPrexArgInfo;26042605static char *disableCCI=feGetEnv("TR_DisableConstClassInlining");2606static char *pEnvconstClassWeight=feGetEnv("TR_constClassWeight");2607static int constClassWeight = pEnvconstClassWeight ? atoi(pEnvconstClassWeight) : DEFAULT_CONST_CLASS_WEIGHT;26082609int32_t fraction = comp()->getOptions()->getInlinerArgumentHeuristicFraction();2610for(TR_ParameterMapping * parm = map.getFirst(); parm ; parm = parm->getNext())2611{2612if(parm->_parameterNode->getOpCode().isLoadConst())2613{2614weight = weight * (fraction-1) / fraction;2615heuristicTrace(tracer(),"Setting weight to %d because arg is load const.",weight);2616}2617else if (parm->_parameterNode->getOpCodeValue() == TR::aload && parm->_parameterNode->getSymbolReference()->getSymbol()->isConstObjectRef())2618{2619weight = weight * (fraction-1) / fraction;2620heuristicTrace(tracer(),"Setting weight to %d because arg is const object reference.",weight);2621}2622else if (!disableCCI &&2623(parm->_parameterNode->getOpCodeValue() == TR::aloadi) &&2624(parm->_parameterNode->getSymbolReference() == comp()->getSymRefTab()->findJavaLangClassFromClassSymbolRef()))2625{2626weight = constClassWeight;2627heuristicTrace(tracer(),"Setting weight to %d because arg is const Class reference.",weight);2628}2629else if( parm->_parameterNode->getDataType() == TR::Address)2630{2631weight = comp()->fej9()->adjustedInliningWeightBasedOnArgument(weight,parm->_parameterNode, parm->_parmSymbol,comp());2632heuristicTrace(tracer(),"Setting weight to %d after frontend adjusted weight for address parm %p\n",weight,parm->_parameterNode);2633}26342635if (!disableCCI && argInfo)2636{2637TR_PrexArgument *argPrexInfo = argInfo->get(parm->_parmSymbol->getOrdinal());2638if (argPrexInfo && argPrexInfo->hasKnownObjectIndex())2639{2640weight = constClassWeight;2641heuristicTrace(tracer(),"Setting weight to %d because arg is known object parm %p\n",weight,parm->_parameterNode);2642break;2643}2644}2645}26462647weight -= (map.getSize() * 4);2648heuristicTrace(tracer(),"Setting weight to %d (subtracting numArgs*4)", weight);26492650return weight;2651}265226532654//---------------------------------------------------------------------2655// TR_InlinerBase eliminateTailRecursion2656//---------------------------------------------------------------------26572658bool2659TR_MultipleCallTargetInliner::eliminateTailRecursion(2660TR::ResolvedMethodSymbol * calleeSymbol, TR_CallStack * callStack,2661TR::TreeTop * callNodeTreeTop, TR::Node * parent, TR::Node * callNode, TR_VirtualGuardSelection *guard)2662{2663if (comp()->getOption(TR_DisableTailRecursion))2664return false;26652666if (_disableTailRecursion)2667return false;26682669TR::TreeTop * nextTT = callNodeTreeTop->getNextRealTreeTop();2670for (;;)2671{2672if (nextTT->getNode()->getOpCodeValue() == TR::Goto)2673nextTT = nextTT->getNode()->getBranchDestination()->getNextRealTreeTop();2674else if (nextTT->getNode()->getOpCodeValue() == TR::BBEnd)2675nextTT = nextTT->getNextTreeTop()->getNextRealTreeTop();2676else break;2677}26782679if (!nextTT->getNode()->getOpCode().isReturn())2680return false;26812682TR_ResolvedMethod * calleeResolvedMethod = calleeSymbol->getResolvedMethod();2683if (comp()->isDLT() && comp()->getCurrentMethod()->isSameMethod(calleeResolvedMethod))2684return false;2685if (calleeResolvedMethod->numberOfExceptionHandlers() > 0)2686{2687// todo check that none of the parameters are referenced in a catch block...that may not be enough2688if (debug("traceETR"))2689printf("potential to eliminate an eh aware tail recursion to %s\n", tracer()->traceSignature(calleeResolvedMethod));2690return false;2691}26922693if (guard->_kind != TR_NoGuard && calleeResolvedMethod->virtualMethodIsOverridden())2694return false; // we can't generate the correct virtual guard26952696for (TR_CallStack * cs = callStack; cs->_methodSymbol != calleeSymbol; cs = cs->getNext())2697if (cs->_method->numberOfExceptionHandlers() > 0) // || cs->_method->isSynchronized())2698return false;26992700TR::ResolvedMethodSymbol * callerSymbol = callStack->_methodSymbol;27012702if (!callerSymbol->getResolvedMethod()->isSameMethod(calleeResolvedMethod))2703return false; // todo ... handle this case27042705// check for any parms being marked pre-existent or fixed2706//2707bool parmIsFixedOrFinal = false;2708ListIterator<TR::ParameterSymbol> parms(&calleeSymbol->getParameterList());2709for (TR::ParameterSymbol *p = parms.getFirst(); p; p = parms.getNext())2710{2711if (p->getIsPreexistent() || p->getFixedType())2712parmIsFixedOrFinal = true;2713}27142715if (parmIsFixedOrFinal)2716return false;27172718TR::Block * branchDestination = calleeSymbol->getFirstTreeTop()->getNode()->getBlock();27192720TR::Block * block = callNodeTreeTop->getEnclosingBlock();2721if (nextTT->getNode()->getOpCodeValue() != TR::Return && nextTT->getNode()->getFirstChild() != callNode)2722{2723if (nextTT->getNode()->getFirstChild()->getOpCodeValue() != TR::iadd)2724return false;27252726if (nextTT->getNode()->getFirstChild()->getSecondChild() != callNode)2727return false;27282729TR::Node * arithmeticNode = nextTT->getNode()->getFirstChild()->getFirstChild();2730if (arithmeticNode->getReferenceCount() > 1)2731return false;27322733if (block->getPredecessors().empty() || (block->getPredecessors().size() > 1))2734return false;27352736TR::Block * conditionBlock = toBlock(block->getPredecessors().front()->getFrom());2737if (conditionBlock->getSuccessors().size() != 2)2738return false;27392740TR::Block * otherBranch = toBlock(conditionBlock->getSuccessors().front()->getTo() == block ? (*(++conditionBlock->getSuccessors().begin()))->getTo() : conditionBlock->getSuccessors().front()->getTo());2741TR::Node * returnNode = otherBranch->getFirstRealTreeTop()->getNode();2742if (returnNode->getOpCodeValue() != TR::ireturn)2743return false;27442745TR::Node * returnValue = returnNode->getFirstChild();2746if (returnValue->getOpCodeValue() != TR::iconst || returnValue->getInt() != 0)2747return false;27482749if (debug("arithmeticSeries"))2750{2751// idiv2752// imul2753// iload #101[0x12754// iadd2755// iload #101[02756// iconst 12757// iconst 22758TR::TreeTop * ifTreeTop = conditionBlock->getLastRealTreeTop();27592760TR::TreeTop::create(comp(), ifTreeTop->getPrevTreeTop(),2761TR::Node::create(TR::ireturn, 1,2762TR::Node::create(TR::idiv, 2,2763TR::Node::create(TR::imul, 2,2764arithmeticNode,2765TR::Node::create(TR::iadd, 2,2766arithmeticNode,2767TR::Node::create(returnNode, TR::iconst, 0, 1))),2768TR::Node::create(returnNode, TR::iconst, 0, 2))));276927702771callerSymbol->removeTree(ifTreeTop);2772TR::CFG * cfg = callerSymbol->getFlowGraph();2773cfg->removeEdge(conditionBlock->getSuccessors().front());2774cfg->removeEdge(*(++conditionBlock->getSuccessors().begin()));2775cfg->addEdge(conditionBlock, cfg->getEnd());2776return true;2777}27782779TR::DataType dt = TR::Int32;2780TR::SymbolReference * temp = comp()->getSymRefTab()->createTemporary(calleeSymbol, dt);2781returnNode->setAndIncChild(0, TR::Node::createLoad(returnNode, temp));2782returnValue->decReferenceCount();2783TR::Block * generatedFirstBlock = calleeSymbol->prependEmptyFirstBlock();2784generatedFirstBlock->setFrequency(conditionBlock->getFrequency());2785generatedFirstBlock->append(TR::TreeTop::create(comp(), TR::Node::createStore(temp, returnValue)));2786arithmeticNode = TR::Node::copy(arithmeticNode);2787arithmeticNode->decReferenceCount();2788TR::TreeTop::create(comp(), callNodeTreeTop->getPrevTreeTop(),2789TR::Node::createStore(temp, TR::Node::create(TR::iadd, 2, TR::Node::createLoad(returnNode, temp), arithmeticNode)));2790}27912792if (!performTransformation(comp(), "%sEliminating tail recursion to %s\n", OPT_DETAILS, tracer()->traceSignature(calleeResolvedMethod)))2793return false;27942795//please don't move this if. It needs to be done after all early exits but exactly before2796//we do any transformations2797if (!comp()->incInlineDepth(calleeSymbol, callNode, !callNode->getOpCode().isCallIndirect(), guard, calleeResolvedMethod->classOfMethod(), 0))2798{2799return false;2800}280128022803_disableInnerPrex = true;28042805TR::CFG * callerCFG = callerSymbol->getFlowGraph();2806TR::TreeTop * prevTreeTop = callNodeTreeTop->getPrevTreeTop();28072808if (parent->getOpCode().isNullCheck())2809prevTreeTop = parent->extractTheNullCheck(prevTreeTop);28102811assignArgumentsToParameters(calleeSymbol, prevTreeTop, callNode);28122813TR::CFGEdge * backEdge;2814if (guard->_kind != TR_NoGuard)2815{2816// TR::Block *block2 = block->split(callNodeTreeTop, callerCFG);2817// block->append(TR::TreeTop::create(comp(), createVirtualGuard(callNode, callNode->getSymbol()->castToResolvedMethodSymbol(), branchDestination->getEntry(), false, (void *)calleeResolvedMethod->classOfMethod(), false)));2818// // branchDestination->setIsCold(); <--- branch destination is NOT cold2819// block2->setIsCold();2820// backEdge = TR::CFGEdge::createEdge(block, branchDestination, trMemory());2821// callerCFG->addEdge(backEdge);28222823TR::Block *gotoBlock = block->split(callNodeTreeTop, callerCFG);2824TR::Block *block2 = gotoBlock->split(callNodeTreeTop, callerCFG);28252826TR::Node *gotoNode = TR::Node::create(callNode, TR::Goto);2827gotoNode->setBranchDestination(branchDestination->getEntry());2828gotoBlock->append(TR::TreeTop::create(comp(), gotoNode));28292830// calleeResolvedMethod will be inlined with a virtual guard v.2831// At this point we need to create another virtual guard v' for the2832// recursive call. v' needs a calleeIndex that is different from the one2833// for v (otherwise we cannot distinguish between the two virtual guards)2834// We achieve this by artificially incrementing the inlining depth as if2835// we inlined calleeResolvedMethod again.28362837TR::Node *vguardNode = createVirtualGuard(callNode,2838callNode->getSymbol()->castToResolvedMethodSymbol(),2839block2->getEntry(),2840comp()->getCurrentInlinedSiteIndex(),//branchDestination->getEntry()->getNode()->getInlinedSiteIndex(),2841calleeResolvedMethod->classOfMethod(), false, guard);2842block->append(TR::TreeTop::create(comp(), vguardNode));2843callerCFG->addEdge(block, block2);28442845TR::CFGEdge *origEdge = gotoBlock->getSuccessors().front();2846backEdge = TR::CFGEdge::createEdge(gotoBlock, branchDestination, trMemory());2847callerCFG->addEdge(backEdge);2848callerCFG->removeEdge(origEdge);2849if (guard->_kind == TR_ProfiledGuard)2850{2851if (block->getFrequency() < 0)2852block2->setFrequency(block->getFrequency());2853else2854{2855if (guard->isHighProbablityProfiledGuard())2856block2->setFrequency(MAX_COLD_BLOCK_COUNT+1);2857else2858block2->setFrequency(TR::Block::getScaledSpecializedFrequency(block->getFrequency()));2859}2860}2861else2862{2863block2->setFrequency(VERSIONED_COLD_BLOCK_COUNT);2864block2->setIsCold();2865}2866}2867else2868{2869callNodeTreeTop->setNode(TR::Node::create(callNode, TR::Goto, 0, branchDestination->getEntry()));2870TR_ASSERT((block->getSuccessors().size() == 1), "eliminateTailRecursion, block with call does not have exactly 1 successor");2871TR::CFGEdge * existingSuccessorEdge = block->getSuccessors().front();2872backEdge = TR::CFGEdge::createEdge(block, branchDestination, trMemory());2873callerCFG->addEdge(backEdge);2874callerCFG->removeEdge(existingSuccessorEdge);2875if (block->getLastRealTreeTop() != callNodeTreeTop)2876callerSymbol->removeTree(block->getLastRealTreeTop());2877TR_ASSERT(block->getLastRealTreeTop() == callNodeTreeTop, "eliminateTailRecursion call isn't last or second last tree in block");2878}28792880if (comp()->getProfilingMode() == JitProfiling)2881{2882TR::Node *asyncNode = TR::Node::createWithSymRef(callNode, TR::asynccheck, 0, comp()->getSymRefTab()->findOrCreateAsyncCheckSymbolRef(comp()->getMethodSymbol()));2883block->prepend(TR::TreeTop::create(comp(), asyncNode));2884}28852886backEdge->setCreatedByTailRecursionElimination(true);2887calleeSymbol->setMayHaveLoops(true);2888comp()->decInlineDepth(); // undo what we artificially did before2889return true;2890}28912892void2893TR_MultipleCallTargetInliner::assignArgumentsToParameters(TR::ResolvedMethodSymbol * calleeSymbol, TR::TreeTop * prevTreeTop, TR::Node * callNode)2894{2895int32_t i = callNode->getFirstArgumentIndex();2896ListIterator<TR::ParameterSymbol> parms(&calleeSymbol->getParameterList());2897for (TR::ParameterSymbol * p = parms.getFirst(); p; ++i, p = parms.getNext())2898{2899TR::SymbolReference * sr = comp()->getSymRefTab()->findOrCreateAutoSymbol(calleeSymbol, p->getSlot(), p->getDataType(), true);2900TR::Node * arg = callNode->getChild(i);2901if (arg->getReferenceCount() != 1 || !arg->getOpCode().hasSymbolReference() || arg->getSymbolReference() != sr)2902{2903arg->decReferenceCount(); // logically remove it from the call noe29042905// Consider,2906// void foo(int a, int b) { .... return foo(b, a); }2907// We're going to create 'a = b; b = a;' which will assign the modified value of 'a' to 'b'.2908// To get the original value of 'a' assigned to 'b' we2909// create a treetop before the assignments so that 'a' is evaluated before it is modified.2910//2911prevTreeTop = TR::TreeTop::create(comp(), prevTreeTop, TR::Node::create(TR::treetop, 1, arg));29122913TR::Node *storeNode = TR::Node::createStore(sr, arg);29142915TR::TreeTop::create(comp(), prevTreeTop, storeNode);2916TR::Node * newArg = TR::Node::createLoad(arg, sr);29172918if (arg->getType().isBCD())2919{2920storeNode->setDecimalPrecision(arg->getDecimalPrecision());2921newArg->setDecimalPrecision(arg->getDecimalPrecision());2922}29232924if (i == 1 && i == callNode->getFirstArgumentIndex() && callNode->getChild(0)->getChild(0) == arg)2925{2926arg->decReferenceCount();2927callNode->getChild(0)->setAndIncChild(0, newArg);2928}2929callNode->setAndIncChild(i, newArg);2930}2931}2932}29332934TR_MultipleCallTargetInliner::TR_MultipleCallTargetInliner(TR::Optimizer *optimizer, TR::Optimization *optimization)2935: TR_InlinerBase(optimizer, optimization)2936{29372938}293929402941void2942TR_MultipleCallTargetInliner::walkCallSite(2943TR::ResolvedMethodSymbol * calleeSymbol, TR_CallStack * callStack,2944TR::TreeTop * callNodeTreeTop, TR::Node * parent, TR::Node * callNode, TR_VirtualGuardSelection *guard,2945TR_OpaqueClassBlock * thisClass, bool inlineNonRecursively, int32_t walkDepth)2946{2947TR::ResolvedMethodSymbol * callerSymbol = callStack->_methodSymbol;29482949int32_t bytecodeSize = getPolicy()->getInitialBytecodeSize(calleeSymbol->getResolvedMethod(), calleeSymbol, comp());29502951///comp()->getFlowGraph()->setMaxFrequency(-1);2952///comp()->getFlowGraph()->setMaxEdgeFrequency(-1);29532954TR_J9InnerPreexistenceInfo innerPrexInfo(comp(), calleeSymbol, callStack, callNodeTreeTop, callNode, guard->_kind);29552956bool genILSucceeded = false;2957vcount_t visitCount = comp()->getVisitCount();2958if (!calleeSymbol->getFirstTreeTop())2959{2960//if (comp()->trace(inlining))2961dumpOptDetails(comp(), "O^O INLINER: Peeking into the IL from walkCallSites as part of the inlining heuristic for [%p]\n", calleeSymbol);29622963//comp()->setVisitCount(1);2964genILSucceeded = (NULL != calleeSymbol->getResolvedMethod()->genMethodILForPeekingEvenUnderMethodRedefinition(calleeSymbol, comp()));2965//comp()->setVisitCount(visitCount);2966}29672968dumpOptDetails(comp(), " -- %s\n", genILSucceeded? "succeeded" : "failed");29692970///if (!inlineNonRecursively && calleeSymbol->mayHaveInlineableCall())29712972if (!inlineNonRecursively && genILSucceeded && calleeSymbol->mayHaveInlineableCall())2973{2974walkCallSites(calleeSymbol, callStack, &innerPrexInfo, walkDepth+1);2975}2976//calleeSymbol->setFirstTreeTop(NULL); // We can reuse the peeked trees. If we're doing real ILGen, the trees will be re-created anyway.2977}29782979void2980TR_MultipleCallTargetInliner::walkCallSites(TR::ResolvedMethodSymbol * callerSymbol, TR_CallStack * prevCallStack, TR_InnerPreexistenceInfo *innerPrexInfo, int32_t walkDepth)2981{2982heuristicTrace(tracer(),"**WalkCallSites: depth %d\n",walkDepth);2983if (walkDepth > MAX_ECS_RECURSION_DEPTH / 4 )2984return;29852986TR_InlinerDelimiter delimiter(tracer(),"walkCallSites");29872988TR_CallStack callStack(comp(), callerSymbol, callerSymbol->getResolvedMethod(), prevCallStack, 0);29892990if (innerPrexInfo)2991callStack._innerPrexInfo = innerPrexInfo;29922993if (prevCallStack == 0)2994callStack.initializeControlFlowInfo(callerSymbol);29952996bool currentBlockHasExceptionSuccessors = false;2997bool prevDisableTailRecursion = _disableTailRecursion;2998bool prevDisableInnerPrex = _disableInnerPrex;2999_disableTailRecursion = false;3000_disableInnerPrex = false;30013002bool isCold = false;3003for (TR::TreeTop * tt = callerSymbol->getFirstTreeTop(); tt && (walkDepth==0); tt = tt->getNextTreeTop())3004{3005TR::Node * parent = tt->getNode();30063007if (parent->getOpCodeValue() == TR::BBStart)3008{3009isCold = false;3010TR::Block *block = parent->getBlock();30113012if (prevCallStack == 0 && !block->isExtensionOfPreviousBlock())3013callStack.makeBasicBlockTempsAvailable(_availableBasicBlockTemps);30143015// dont inline into cold blocks3016//3017if (block->isCold() ||3018!block->getExceptionPredecessors().empty())3019{3020isCold = true;3021}30223023currentBlockHasExceptionSuccessors = !block->getExceptionSuccessors().empty();30243025if (prevCallStack == 0)3026callStack.updateState(block);3027_isInLoop = callStack._inALoop;3028}3029else if (parent->getNumChildren())3030{3031TR::Node * node = parent->getChild(0);3032if (node->getOpCode().isCall() && node->getVisitCount() != _visitCount)3033{3034TR::Symbol *sym = node->getSymbol();3035if (!isCold)3036{30373038///TR::ResolvedMethodSymbol * calleeSymbol = isInlineable(&callStack, node, guard, thisClass,tt);3039TR::SymbolReference *symRef = node->getSymbolReference();3040TR::MethodSymbol *calleeSymbol = symRef->getSymbol()->castToMethodSymbol();30413042//TR_CallSite *callsite = new (trStackMemory()) TR_CallSite (symRef->getOwningMethod(comp()), tt, parent, node, calleeSymbol->getMethod(), 0, (int32_t)symRef->getOffset(), symRef->getCPIndex(), 0, calleeSymbol->getResolvedMethodSymbol(), node->getOpCode().isCallIndirect(), calleeSymbol->isInterface(), node->getByteCodeInfo(), comp());304330443045TR_CallSite *callsite = TR_CallSite::create(tt, parent, node,30460, symRef, (TR_ResolvedMethod*) 0,3047comp(), trMemory() , stackAlloc);304830493050debugTrace(tracer(),"**WalkCallSites: Analysing Call at call node %p . Creating callsite %p to encapsulate call.",node,callsite);3051getSymbolAndFindInlineTargets(&callStack, callsite);30523053heuristicTrace(tracer(),"**WalkCallSites:Searching for Targets returned %d targets for call at node %p. ",callsite->numTargets(),node);30543055///if (calleeSymbol)3056if (callsite->numTargets())3057{3058bool flag=false;3059for(int32_t i=0 ; i < callsite->numTargets() && flag==false; i++)3060{30613062// TR::ResolvedMethodSymbol *calleeResolvedSymbol = calleeSymbol->getResolvedMethodSymbol();3063// if (!calleeResolvedSymbol)3064// continue;30653066bool walkCall = false;30673068if (! (3069callsite->getTarget(i)->_calleeSymbol->isVMInternalNative() ||3070callsite->getTarget(i)->_calleeSymbol->isHelper() ||3071callsite->getTarget(i)->_calleeSymbol->isNative() ||3072callsite->getTarget(i)->_calleeSymbol->isSystemLinkageDispatch() ||3073callsite->getTarget(i)->_calleeSymbol->isJITInternalNative() ||3074callsite->getTarget(i)->_calleeSymbol->getResolvedMethod()->isAbstract()3075))3076{3077if (TR::Compiler->mtd.isCompiledMethod(callsite->getTarget(i)->_calleeSymbol->getResolvedMethod()->getPersistentIdentifier()))3078{3079TR_PersistentJittedBodyInfo * bodyInfo = ((TR_ResolvedJ9Method*) callsite->getTarget(i)->_calleeSymbol->getResolvedMethodSymbol()->getResolvedMethod())->getExistingJittedBodyInfo();3080if (bodyInfo &&3081bodyInfo->getHotness() < warm &&3082!bodyInfo->getIsProfilingBody())3083walkCall = true;3084}3085else3086walkCall = true;3087}3088if (symRef->getOwningMethodSymbol(comp()) != callerSymbol)3089{3090walkCall = false;3091}30923093if (walkCall)3094{3095// TR_ResolvedMethod * calleeResolvedMethod = calleeResolvedSymbol->getResolvedMethod();3096TR_CallStack * cs = callStack.isCurrentlyOnTheStack(callsite->getTarget(i)->_calleeMethod, 1);3097TR_PersistentMethodInfo * methodInfo = TR_PersistentMethodInfo::get(callsite->getTarget(i)->_calleeMethod); //calleeResolvedMethod);3098bool alreadyVisited = false;30993100if (methodInfo && methodInfo->wasScannedForInlining())3101{3102//printf("Already visited\n");3103debugTrace(tracer(),"Walk call sites for scanning: methodInfo %p already visited\n", methodInfo);31043105alreadyVisited = true;3106}31073108if (!(!alreadyVisited &&3109cs &&3110callsite->getTarget(i)->_calleeSymbol == callsite->_callNode->getSymbol() &&3111eliminateTailRecursion(cs->_methodSymbol, &callStack, callsite->_callNodeTreeTop, callsite->_parent, callsite->_callNode, callsite->getTarget(i)->_guard)))3112{3113// walkCallSite(calleeResolvedSymbol, &callStack, tt, parent, node, guard, thisClass, false, walkDepth);3114walkCallSite(callsite->getTarget(i)->_calleeSymbol, &callStack,callsite->_callNodeTreeTop,callsite->_parent,callsite->_callNode,callsite->getTarget(i)->_guard,callsite->getTarget(i)->_receiverClass,false,walkDepth);3115debugTrace(tracer(),"Walk call sites for scanning: at call site: %s\n", tracer()->traceSignature(callsite->getTarget(i)->_calleeSymbol));31163117// TR::SymbolReference * symRef = node->getSymbolReference();3118// TR_CallSite *callsite = new (trStackMemory()) TR_CallSite (symRef->getOwningMethod(comp()),3119// tt,3120// parent,3121// node,3122// calleeResolvedSymbol->getMethod(),3123// 0,3124// (int32_t)symRef->getOffset(),3125// symRef->getCPIndex(),3126// 0,3127// calleeResolvedSymbol->getResolvedMethodSymbol(),3128// node->getOpCode().isCallIndirect(),3129// calleeResolvedSymbol->isInterface(),3130// node->getByteCodeInfo(),3131// comp());31323133weighCallSite(&callStack, callsite, currentBlockHasExceptionSuccessors, true);31343135if(tracer()->debugLevel())3136{3137tracer()->dumpCallSite(callsite, "Dumping Call Site after Weighing");3138}31393140if (methodInfo)3141{3142methodInfo->setWasScannedForInlining(true);3143debugTrace(tracer(),"Walk call sites for scanning: set scaneed for methodInfo %p\n", methodInfo);3144}3145//printf("Walk %s, method info %p\n", calleeResolvedSymbol->signature(trMemory()), methodInfo);3146}3147}3148}3149} //end for loop over call targets3150}3151node->setVisitCount(_visitCount);3152}3153}3154}31553156_disableTailRecursion = prevDisableTailRecursion;3157_disableInnerPrex = prevDisableInnerPrex;3158}31593160bool TR_MultipleCallTargetInliner::inlineCallTargets(TR::ResolvedMethodSymbol *callerSymbol, TR_CallStack *prevCallStack, TR_InnerPreexistenceInfo *innerPrexInfo)3161{3162TR_InlinerDelimiter delimiter(tracer(),"TR_MultipleCallTargetInliner::inlineCallTargets");31633164TR_CallStack callStack(comp(), callerSymbol, callerSymbol->getResolvedMethod(), prevCallStack, 0, true);31653166if (innerPrexInfo)3167callStack._innerPrexInfo = innerPrexInfo;31683169if (prevCallStack == 0)3170callStack.initializeControlFlowInfo(callerSymbol);31713172bool anySuccess = false;3173bool anySuccess2 = false;31743175bool currentBlockHasExceptionSuccessors = false;31763177bool prevDisableTailRecursion = _disableTailRecursion;3178bool prevDisableInnerPrex = _disableInnerPrex;3179bool prevInliningAsWeWalk = _inliningAsWeWalk;31803181_disableTailRecursion = false;3182_disableInnerPrex = false;3183bool isCold = false;31843185{3186TR_InlinerDelimiter delimiter(tracer(),"collectTargets");31873188int32_t thisCallSite = callerSymbol->getFirstTreeTop()->getNode()->getInlinedSiteIndex();31893190TR::TreeTop *nextTree = NULL;3191for (TR::TreeTop * tt = callerSymbol->getFirstTreeTop(); tt; tt = nextTree)3192{3193// Inlining can add code downstream of our traversal. We need to skip that code.3194//3195nextTree = tt->getNextTreeTop();31963197TR::Node * parent = tt->getNode();31983199if (prevCallStack)3200_inliningAsWeWalk = true;32013202if (parent->getOpCodeValue() == TR::BBStart)3203{3204isCold = false;3205TR::Block *block = parent->getBlock();32063207if (prevCallStack == 0 && !block->isExtensionOfPreviousBlock())3208callStack.makeBasicBlockTempsAvailable(_availableBasicBlockTemps);32093210// dont inline into cold blocks3211if (block->isCold() || !block->getExceptionPredecessors().empty())3212{3213isCold = true;3214}32153216// FIXME: the following assumes that catch blocks are at the end of the method3217// which may not generally be true. Correct fix is to do either dom-pdom or3218// structural analysis before this opt, and mark the cold-paths, and skipping3219// cold blocks would automagically do the trick3220//3221//if (!block->getExceptionPredecessors().empty())3222// break; // dont inline into catch blocks32233224currentBlockHasExceptionSuccessors = !block->getExceptionSuccessors().empty();32253226if (prevCallStack == 0)3227callStack.updateState(block);3228}3229else if (parent->getNumChildren())3230{3231TR::Node * node = parent->getChild(0);3232if (node->getOpCode().isFunctionCall() && node->getVisitCount() != _visitCount)3233{3234TR_CallStack::SetCurrentCallNode sccn(callStack, node);32353236TR::Symbol *sym = node->getSymbol();3237if (!isCold && !node->isTheVirtualCallNodeForAGuardedInlinedCall())3238{3239TR::SymbolReference * symRef = node->getSymbolReference();3240TR::MethodSymbol * calleeSymbol = symRef->getSymbol()->castToMethodSymbol();32413242TR_CallSite *callsite = TR_CallSite::create(tt, parent, node,32430, symRef, (TR_ResolvedMethod*) 0,3244comp(), trMemory() , stackAlloc);32453246if (prevCallStack==0)3247{3248heuristicTrace(tracer(),"\n");3249heuristicTrace(tracer(),"^^^ Top Level: Analysing Call at call node %p . Creating callsite %p to encapsulate call.",node,callsite);3250}32513252getSymbolAndFindInlineTargets(&callStack, callsite);32533254if (!prevCallStack && callsite->numTargets() > 0)3255{3256// buildPrexArgInfo and propagateArgs use the caller symbol to look up the invoke bytecode.3257// In a pass of inliner after the first (which happens in JSR292), the invoke bytecode won't3258// be in the top-level method's bytecode, and the caller can vary with the call node.3259TR::ResolvedMethodSymbol *thisCallSiteCallerSymbol = node->getSymbolReference()->getOwningMethodSymbol(comp());3260TR_PrexArgInfo* compArgInfo = TR_PrexArgInfo::buildPrexArgInfoForMethodSymbol(thisCallSiteCallerSymbol, tracer());32613262if (tracer()->heuristicLevel())3263{3264alwaysTrace(tracer(), "compArgInfo :");3265compArgInfo->dumpTrace();3266}3267compArgInfo->clearArgInfoForNonInvariantArguments(thisCallSiteCallerSymbol, tracer());3268TR_PrexArgInfo::propagateArgsFromCaller(thisCallSiteCallerSymbol, callsite, compArgInfo, tracer());3269if (tracer()->heuristicLevel())3270{3271alwaysTrace(tracer(), "callsite->getTarget(0)->_ecsPrexArgInfo :");3272callsite->getTarget(0)->_ecsPrexArgInfo->dumpTrace();3273}3274}32753276heuristicTrace(tracer(),"Searching for Targets returned %d targets for call at node %p. ",callsite->numTargets(),node);32773278if (callsite->numTargets())3279{3280bool flag = false;3281for (int32_t i = 0; i < callsite->numTargets() && flag == false; i++)3282{3283TR_CallStack *cs = callStack.isCurrentlyOnTheStack(callsite->getTarget(i)->_calleeMethod,1);3284if (cs && callsite->getTarget(i)->_calleeSymbol == node->getSymbol() &&3285eliminateTailRecursion( cs->_methodSymbol, &callStack, callsite->_callNodeTreeTop, callsite->_parent,callsite->_callNode,callsite->getTarget(i)->_guard) )3286{3287anySuccess2 = true;3288flag = true;3289}3290}32913292if (!flag)3293{3294if (prevCallStack == 0)//we only weigh base level calls.. All other calls we proceed right to inlining3295{3296weighCallSite(&callStack, callsite, currentBlockHasExceptionSuccessors);32973298if (tracer()->debugLevel())3299{3300tracer()->dumpCallSite(callsite, "Dumping Call Site after Weighing");3301}3302}3303else3304{3305// with !comp()->getOption(TR_DisableNewInliningInfrastructure)3306// prevCallStack == 0 will always be true?33073308for (int32_t i=0; i<callsite->numTargets(); i++)3309{3310heuristicTrace(tracer(),"call depth > 0 . Inlining call at node %p",node);3311anySuccess2 |= inlineCallTarget(&callStack, callsite->getTarget(i), true);3312}3313}3314}3315else3316{3317// when flag is true do nothing3318}3319}3320else3321{3322heuristicTrace(tracer(),"Found No Inlineable targets for call at node %p\n",node);3323debugTrace(tracer(),"Adding callsite %p to list of deadCallSites",callsite);3324_deadCallSites.add(callsite);3325}3326}3327else3328{3329TR::SymbolReference * symRef = node->getSymbolReference();3330TR::MethodSymbol * calleeSymbol = symRef->getSymbol()->castToMethodSymbol();3331heuristicTrace(tracer(),"Block containing call node %p %s. Skipping call.", node, node->isTheVirtualCallNodeForAGuardedInlinedCall() ? "is on the cold side of a guard" : "is cold");3332tracer()->insertCounter(Cold_Block,tt);3333}33343335node->setVisitCount(_visitCount);3336}3337else if (node->getOpCode().isCall())3338{3339debugTrace(tracer(),"Failing for an unknown reason. TreeTop = %p, node = %p nodevisitCount = %d _visitCount = %d getInlinedSiteIndex() = %d thisCallSite = %d. ",3340tt, node, node->getVisitCount(), _visitCount,node->getInlinedSiteIndex(),thisCallSite);3341}3342}3343}3344}33453346for (TR_CallTarget *target = _callTargets.getFirst(); target; target = target->getNext())3347target->_prexArgInfo = getUtil()->computePrexInfo(target);33483349if (prevCallStack == 0)3350{3351TR_InlinerDelimiter delimiter(tracer(),"refineCallgraph");33523353int32_t size = getPolicy()->getInitialBytecodeSize(callerSymbol, comp());3354int32_t limit = _callerWeightLimit;3355int32_t totalWeight=0;33563357TR_CallTarget * calltarget = NULL;33583359if (comp()->getOption(TR_TraceAll))3360{3361traceMsg(comp(), "\n\n~~~ Call site weights for %s\n", comp()->signature());3362traceMsg(comp(), "original size: %d\n", size);3363traceMsg(comp(), "Inlining weight limit: %d\n", limit);3364totalWeight = 0;3365for (calltarget = _callTargets.getFirst(); calltarget; calltarget = calltarget->getNext())3366{3367totalWeight += calltarget->_weight;3368traceMsg(comp(), "Calltarget %p callnode %p %s\n", calltarget, &calltarget->_myCallSite->_callNode, tracer()->traceSignature(calltarget->_calleeSymbol));3369traceMsg(comp(), "Site size: %d site weight %d call-graph adjusted weight %lf, total weight %d\n", calltarget->_size, calltarget->_weight, calltarget->_callGraphAdjustedWeight, totalWeight);3370}3371}33723373static const char * p = feGetEnv("TR_TrivialWeightForLimit");3374int32_t trivialWeightForLimit = 30;33753376if (p)3377{3378trivialWeightForLimit = atoi(p);3379printf("Using trivial weight limit of %d\n", trivialWeightForLimit);3380}33813382TR_CallTarget* callTargetToChop = NULL;3383{3384bool doneInlining = false;3385int32_t totalWeight = 0;3386TR_CallTarget * prev = 0;3387for (calltarget = _callTargets.getFirst(); calltarget; prev = calltarget, calltarget = calltarget->getNext())3388{3389totalWeight += calltarget->_weight;3390if (doneInlining)3391tracer()->insertCounter(Exceeded_Caller_Budget,calltarget->_myCallSite->_callNodeTreeTop);3392else if (totalWeight > limit && calltarget->_weight > trivialWeightForLimit)3393{3394callTargetToChop = calltarget;3395doneInlining = true;3396}3397}3398}33993400TR_CallTarget * prev = 0;3401int32_t estimatedNumberOfNodes = getCurrentNumberOfNodes();3402debugTrace(tracer(), "Initially, estimatedNumberOfNodes = %d\n", estimatedNumberOfNodes);3403for (calltarget = _callTargets.getFirst(); calltarget != callTargetToChop; prev = calltarget, calltarget = calltarget->getNext())3404{3405generateNodeEstimate myEstimate;3406recursivelyWalkCallTargetAndPerformAction(calltarget, myEstimate);3407estimatedNumberOfNodes += myEstimate.getNodeEstimate();34083409debugTrace(tracer(),"Estimated Number of Nodes is %d after calltarget %p",estimatedNumberOfNodes,calltarget);34103411float factor = 1.1F; // this factor was chosen based on a study of a large WAS app that showed that getMaxBytecodeindex was 92% accurate compared to nodes generated34123413if ((uint32_t)(estimatedNumberOfNodes*factor) > _nodeCountThreshold)3414{3415callTargetToChop = calltarget;3416debugTrace(tracer(),"estimate nodes exceeds _nodeCountThreshold, chopped off targets staring from %p, lastTargetToInline %p\n", callTargetToChop, prev);3417break;3418}3419}34203421processChoppedOffCallTargets(prev, callTargetToChop, estimatedNumberOfNodes);3422if (comp()->getOption(TR_TraceAll) || tracer()->heuristicLevel())3423{3424tracer()->dumpCallGraphs(&_callTargets);3425tracer()->dumpDeadCalls(&_deadCallSites);3426}3427}34283429if (prevCallStack == 0)3430{3431for (TR_CallTarget* calltarget = _callTargets.getFirst(); calltarget; calltarget = calltarget->getNext())3432{3433debugTrace(tracer(), "marking calltarget %p of %p as MT_Marked", calltarget, calltarget->_myCallSite);3434calltarget->_failureReason = MT_Marked;3435}34363437for (TR_CallTarget* calltarget = _callTargets.getFirst(); calltarget; calltarget = calltarget->getNext())3438{3439TR_CallSite* clSite = calltarget->_myCallSite;3440for (int i = 0 ; i < clSite->numTargets(); i++)3441{3442if (clSite->getTarget(i)->_failureReason != MT_Marked)3443{3444debugTrace(tracer(), "removing calltarget %p of %p as it isn't in _callTargets", clSite->getTarget(i), calltarget->_myCallSite);3445clSite->removecalltarget(i, tracer(), Not_Sane);3446i--;3447}3448}3449}3450}34513452if (prevCallStack == 0)3453{3454TR_InlinerDelimiter delimiter(tracer(),"inlineTransformation");34553456TR_CallTarget * calltarget = NULL;34573458heuristicTrace(tracer(),"Starting Transformation Phase\n");3459//static int si, sj;3460//printf("graph exceeded %d times out of %d", (calltarget ? ++si : si) , ++sj);34613462// We must inline in tree order because of the way temp sharing is done.3463// there are two types of temporaries inliner generates - availablebasicblocktemps, which are used when inlining breaks a block, and commoning must be broken and3464// availableTemps, which are generally used for when a parameter needs a temporary created for it.3465// all the methods that deal with temps (parametertoargumentmapper, handleinjectedbasicblock,transforminlinedfunction) will consult these lists3466// usually, it will search a list, and if it doesn't find a temp, search the second list.3467// the problem is when inlining out of order and with the fact that both temp lists can be consulted, it is possible that a temp will get misused.3468// an example will be a call lower down was inlined first and created a temp t1, for a parameter (the block doesn't get split). It gets added to availableTemps after inlining.3469// After, higher up (in the same block) another call now gets inlined, and splits the block. handleinjectedbasicblock now goes and breaks commoning around this higher up call.3470// when this happens, it can grab the temp t1 from the availableTemps list and reuse it for breaking commoning. Now there are two stores to t1 in the same block. If there was any3471// commoning that existed after the second store to t1 that was supposed to get broken, it will now load a bad value of t1.347234733474for (TR::TreeTop * tt = callerSymbol->getFirstTreeTop(); tt; tt = tt->getNextTreeTop())3475{3476TR::Node * parent = tt->getNode();3477if (tt->getNode()->getNumChildren() && tt->getNode()->getChild(0)->getOpCode().isCall())3478{3479debugTrace(tracer()," (Second Iteration) Found a call at tt %p node %p",tt,tt->getNode());3480TR_CallStack::SetCurrentCallNode sccn(callStack, tt->getNode()->getChild(0));3481for (calltarget = _callTargets.getFirst(); calltarget; calltarget = calltarget->getNext())3482{3483if(tracer()->debugLevel())3484debugTrace(tracer()," (Second Iteration) Considering call target %p ByteCodeIndex = %d calltarget->_myCallSite->_callNodeTreeTop = %p"3485" alreadyInlined = %d signature = %s",3486calltarget,calltarget->_myCallSite->_callNode->getByteCodeIndex(),calltarget->_myCallSite->_callNodeTreeTop,3487calltarget->_alreadyInlined,tracer()->traceSignature(calltarget->_calleeSymbol));34883489if (calltarget->_myCallSite->_callNodeTreeTop == tt && !calltarget->_alreadyInlined)3490{3491TR::TreeTop* oldTt = tt;3492bool success = inlineCallTarget(&callStack, calltarget, true, NULL, &tt);3493anySuccess |= success;3494debugTrace(tracer(), "(Second Iteration) call target %p node %p. success = %d anySuccess = %d",calltarget, oldTt->getNode(),success,anySuccess);3495}3496}3497}3498if (parent->getOpCodeValue() == TR::BBStart &&3499!parent->getBlock()->isExtensionOfPreviousBlock())3500callStack.makeBasicBlockTempsAvailable(_availableBasicBlockTemps);3501}3502}35033504_disableTailRecursion = prevDisableTailRecursion;3505_disableInnerPrex = prevDisableInnerPrex;3506_inliningAsWeWalk = prevInliningAsWeWalk;35073508callStack.commit();3509return anySuccess;3510}35113512void TR_MultipleCallTargetInliner::weighCallSite( TR_CallStack * callStack , TR_CallSite *callsite, bool currentBlockHasExceptionSuccessors, bool dontAddCalls)3513{3514TR_J9InlinerPolicy *j9inlinerPolicy = (TR_J9InlinerPolicy *) getPolicy();3515TR_InlinerDelimiter delimiter(tracer(), "weighCallSite");35163517for (int32_t k = 0; k < callsite->numTargets(); k++)3518{3519uint32_t size = 0;35203521TR_EstimateCodeSize::raiiWrapper ecsWrapper(this, tracer(), _maxRecursiveCallByteCodeSizeEstimate);3522TR_EstimateCodeSize *ecs = ecsWrapper.getCodeEstimator();35233524bool possiblyVeryHotLargeCallee = false;3525bool wouldBenefitFromInlining = false;35263527TR_CallTarget *calltarget = callsite->getTarget(k);35283529//for partial inlining:3530calltarget->_originatingBlock = callsite->_callNodeTreeTop->getEnclosingBlock();353135323533heuristicTrace(tracer(),"222 Weighing Call Target %p (node = %p)",calltarget,callsite->_callNode);35343535if (calltarget->_calleeSymbol && calltarget->_calleeSymbol->getResolvedMethod() &&3536comp()->isGeneratedReflectionMethod(calltarget->_calleeSymbol->getResolvedMethod()) &&3537!comp()->isGeneratedReflectionMethod(comp()->getCurrentMethod()))3538return;35393540if (calltarget->_calleeSymbol->getRecognizedMethod() == TR::java_lang_Class_newInstance ||3541calltarget->_calleeSymbol->getRecognizedMethod() == TR::java_util_Arrays_fill ||3542calltarget->_calleeSymbol->getRecognizedMethod() == TR::java_util_Arrays_equals ||3543calltarget->_calleeSymbol->getRecognizedMethod() == TR::java_lang_String_equals ||3544calltarget->_calleeSymbol->getRecognizedMethod() == TR::sun_io_ByteToCharSingleByte_convert ||3545calltarget->_calleeSymbol->getRecognizedMethod() == TR::sun_io_ByteToCharDBCS_EBCDIC_convert ||3546calltarget->_calleeSymbol->getRecognizedMethod() == TR::sun_io_CharToByteSingleByte_convert ||3547calltarget->_calleeSymbol->getRecognizedMethod() == TR::sun_io_ByteToCharSingleByte_JITintrinsicConvert ||3548calltarget->_calleeSymbol->getRecognizedMethod() == TR::java_math_BigDecimal_subMulAddAddMulSetScale)3549{3550//This resetting of visit count is safe to do because all nodes and blocks in Estimate Code Size die once ecs returns3551vcount_t origVisitCount = comp()->getVisitCount();35523553ecs->calculateCodeSize(calltarget, callStack);3554//This resetting of visit count is safe to do because all nodes and blocks in Estimate Code Size die once ecs returns3555comp()->setVisitCount(origVisitCount);35563557if(calltarget->_isPartialInliningCandidate && calltarget->_partialInline)3558calltarget->_partialInline->setCallNodeTreeTop(callsite->_callNodeTreeTop);3559heuristicTrace(tracer(),"Setting size to 10 for recognized call target at node %p",calltarget->_myCallSite->_callNode);3560size = 10;3561}3562else3563{3564if (currentBlockHasExceptionSuccessors && ecs->aggressivelyInlineThrows())3565{3566_maxRecursiveCallByteCodeSizeEstimate <<= 3;3567heuristicTrace(tracer(),"Setting _maxRecursiveCallByteCodeSizeEstimate to %d because current block has exception successors and want to aggressively inline throws 1.",_maxRecursiveCallByteCodeSizeEstimate);3568}3569if (ecs->aggressivelyInlineThrows())3570_EDODisableInlinedProfilingInfo = true;35713572//This resetting of visit count is safe to do because all nodes and blocks in Estimate Code Size die once ecs returns3573vcount_t origVisitCount = comp()->getVisitCount();35743575bool inlineit = ecs->calculateCodeSize(calltarget, callStack);3576//This resetting of visit count is safe to do because all nodes and blocks in Estimate Code Size die once ecs returns3577comp()->setVisitCount(origVisitCount);357835793580debugTrace(tracer()," Original ecs size = %d, _maxRecursiveCallByteCodeSizeEstimate = %d ecs _realSize = %d optimisticSize = %d inlineit = %d error = %s ecs.sizeThreshold = %d",3581size,_maxRecursiveCallByteCodeSizeEstimate,ecs->getSize(),ecs->getOptimisticSize(),inlineit,ecs->getError(),ecs->getSizeThreshold());35823583size = ecs->getSize();35843585if (!inlineit && !callMustBeInlinedRegardlessOfSize(callsite))3586{3587if (isWarm(comp()))3588{3589if (comp()->isServerInlining())3590{3591if (callsite->_callNode->getInlinedSiteIndex() < 0) //Ensures setWarmCallGraphTooBig is only called for methods with inline index -1 (indexes >=0 can happen when inliner is called after inlining has already occured3592comp()->getCurrentMethod()->setWarmCallGraphTooBig (callsite->_callNode->getByteCodeInfo().getByteCodeIndex(), comp());3593else3594heuristicTrace(tracer(),"Not calling setWarmCallGraphTooBig on callNode %p because it is not from method being compiled bc index %d inlinedsiteindex %d",callsite->_callNode,callsite->_callNode->getByteCodeInfo().getByteCodeIndex(),callsite->_callNode->getInlinedSiteIndex());3595if (comp()->trace(OMR::inlining))3596heuristicTrace(tracer(),"inliner: Marked call as warm callee too big: %d > %d: %s\n", size, ecs->getSizeThreshold(), tracer()->traceSignature(calltarget->_calleeSymbol));3597//printf("inliner: Marked call as warm callee too big: %d > %d: %s\n", nonRecursiveSize, sizeThreshold, calleeSymbol->signature(trMemory()));3598}3599}3600tracer()->insertCounter(ECS_Failed,calltarget->_myCallSite->_callNodeTreeTop);3601heuristicTrace(tracer(),"Not Adding Call Target %p to list of targets to be inlined");3602if (comp()->cg()->traceBCDCodeGen())3603{3604traceMsg(comp(), "q^q : failing to inline %s into %s (callNode %p on line_no=%d) due to code size\n",3605tracer()->traceSignature(calltarget->_calleeSymbol),tracer()->traceSignature(callStack->_methodSymbol),3606callsite->_callNode,comp()->getLineNumber(callsite->_callNode));3607}3608continue;3609}36103611if (calltarget->_isPartialInliningCandidate && calltarget->_partialInline)3612calltarget->_partialInline->setCallNodeTreeTop(callsite->_callNodeTreeTop);36133614heuristicTrace(tracer(),"WeighCallSite: For Target %p node %p signature %s, estimation returned a size of %d",3615calltarget,calltarget->_myCallSite->_callNode,tracer()->traceSignature(calltarget),size);36163617if (currentBlockHasExceptionSuccessors && ecs->aggressivelyInlineThrows())3618{3619_maxRecursiveCallByteCodeSizeEstimate >>= 3;3620size >>= 3;3621size = std::max<uint32_t>(1, size);36223623heuristicTrace(tracer(),"Setting size to %d because current block has exception successors and want to aggressively inline throws 2",size);3624}3625if (callMustBeInlinedRegardlessOfSize(calltarget->_myCallSite))3626{3627heuristicTrace(tracer(), "calltarget->_fullSize: %d size: %d", calltarget->_fullSize, size);3628size = 0;3629heuristicTrace(tracer(), "Setting size to %d because call is dominate hot based on PDF", size);3630}363136323633wouldBenefitFromInlining = false;3634possiblyVeryHotLargeCallee = false;3635if ((((comp()->getMethodHotness() == veryHot) &&3636comp()->isProfilingCompilation()) ||3637(comp()->getMethodHotness() == scorching)) &&3638(size > _maxRecursiveCallByteCodeSizeEstimate/2))3639possiblyVeryHotLargeCallee = true;36403641if (calltarget->_calleeSymbol->isSynchronised())3642{3643size >>= 1; // could help gvp3644heuristicTrace(tracer(),"Setting size to %d because call is Synchronized",size);3645if (comp()->getMethodHotness() >= hot)3646{3647size >>= 1; // could help escape analysis as well3648heuristicTrace(tracer(),"Setting size to %d because call is Synchronized and also hot",size);3649}3650wouldBenefitFromInlining = true;3651}36523653if (strstr(calltarget->_calleeSymbol->signature(trMemory()),"BigDecimal.add("))3654{3655size >>=2;3656heuristicTrace(tracer(),"Setting size to %d because call is BigDecimal.add",size);3657}36583659if (isHot(comp()))3660{3661TR_ResolvedMethod *m = calltarget->_calleeSymbol->getResolvedMethod();3662char *sig = "toString";3663if (strncmp(m->nameChars(), sig, strlen(sig)) == 0)3664{3665size >>= 1;3666heuristicTrace(tracer(),"Setting size to %d because call is toString and compile is hot",size);3667}3668else3669{3670sig = "multiLeafArrayCopy";3671if (strncmp(m->nameChars(), sig, strlen(sig)) == 0)3672{3673size >>= 1;3674heuristicTrace(tracer(),"Setting size to %d because call is multiLeafArrayCopy and compile is hot",size);3675}3676}36773678if (calltarget->_calleeSymbol->getRecognizedMethod() == TR::java_math_BigDecimal_valueOf)3679{3680size >>= 2;3681heuristicTrace(tracer(),"Setting size to %d because call is BigDecimal_valueOf and compile is hot",size);3682}3683}36843685int32_t frequency1 = 0, frequency2 = 0;3686int32_t origSize = size;3687bool isCold;3688TR::TreeTop *callNodeTreeTop = calltarget->_myCallSite->_callNodeTreeTop;3689if (callNodeTreeTop)3690{3691// HACK: Get frequency from both sources, and use both. You're3692// only cold if you're cold according to both.36933694frequency1 = comp()->convertNonDeterministicInput(comp()->fej9()->getIProfilerCallCount(callsite->_callNode->getByteCodeInfo(), comp()), MAX_BLOCK_COUNT + MAX_COLD_BLOCK_COUNT, randomGenerator(), 0);3695TR::Block * block = callNodeTreeTop->getEnclosingBlock();3696frequency2 = comp()->convertNonDeterministicInput(block->getFrequency(), MAX_BLOCK_COUNT + MAX_COLD_BLOCK_COUNT, randomGenerator(), 0);36973698TR::TreeTop *tt = callNodeTreeTop;3699while (tt && (frequency2 == -1))3700{3701while (tt->getNode()->getOpCodeValue() != TR::BBStart) tt = tt->getPrevTreeTop();37023703TR::Block *block = NULL;3704if (tt) block = tt->getNode()->getBlock();3705if (block && tt->getNode()->getInlinedSiteIndex()<0)3706{3707frequency2 = comp()->convertNonDeterministicInput(block->getFrequency(), MAX_BLOCK_COUNT + MAX_COLD_BLOCK_COUNT, randomGenerator(), 0);3708}37093710tt = tt->getPrevTreeTop();3711}37123713if ((frequency1 <= 0) && ((0 <= frequency2) && (frequency2 <= MAX_COLD_BLOCK_COUNT)))3714{3715isCold = true;3716}3717// For optServer in hot/scorching I want the old thresholds 1000 0 0 (high degree of inlining)3718// For optSever in warm I want the new thresholds 9000 5000 15003719// For noServer I want no change for high frequency but inhibit inlining in cold blocks ==> 10000 5000 15003720if (TR::isJ9() && !comp()->getMethodSymbol()->doJSR292PerfTweaks() && calltarget->_calleeMethod &&3721!alwaysWorthInlining(calltarget->_calleeMethod, callsite->_callNode))3722{3723int32_t maxFrequency = MAX_BLOCK_COUNT + MAX_COLD_BLOCK_COUNT;3724int32_t borderFrequency = 9000;3725int32_t coldBorderFrequency = 5000;3726int32_t veryColdBorderFrequency = 1500;3727if (comp()->isServerInlining())3728{3729if (comp()->getOption(TR_DisableConservativeInlining) ||3730(comp()->getOptLevel() >= hot) ||3731getJ9InitialBytecodeSize(calltarget->_calleeMethod, 0, comp()) < comp()->getOptions()->getAlwaysWorthInliningThreshold())// use old thresholds3732{3733borderFrequency = 1000;3734coldBorderFrequency = 0;3735veryColdBorderFrequency = 0;3736}3737}3738else3739{3740borderFrequency = 10000;3741if (comp()->getOptLevel() >= hot)3742{3743coldBorderFrequency = 0;3744veryColdBorderFrequency = 0;3745}3746}37473748// Did the user specify specific values? If so, use those3749if (comp()->getOptions()->getInlinerCGBorderFrequency() >= 0)3750borderFrequency = comp()->getOptions()->getInlinerCGBorderFrequency();3751if (comp()->getOptions()->getInlinerCGColdBorderFrequency() >= 0)3752coldBorderFrequency = comp()->getOptions()->getInlinerCGColdBorderFrequency();3753if (comp()->getOptions()->getInlinerCGVeryColdBorderFrequency() >= 0)3754veryColdBorderFrequency = comp()->getOptions()->getInlinerCGVeryColdBorderFrequency();37553756if (comp()->trace(OMR::inlining))3757heuristicTrace(tracer(),"WeighCallSite: Considering shrinking call %p with frequency %d\n", callsite->_callNode, frequency2);37583759bool largeCompiledCallee = !comp()->getOption(TR_InlineVeryLargeCompiledMethods) &&3760isLargeCompiledMethod(calltarget->_calleeMethod, size, frequency2);3761if (largeCompiledCallee)3762{3763size = size*TR::Options::_inlinerVeryLargeCompiledMethodAdjustFactor;3764}3765else if (frequency2 > borderFrequency)3766{3767float factor = (float)(maxFrequency-frequency2)/(float)maxFrequency;3768factor = std::max(factor, 0.4f);37693770float avgMethodSize = (float)size/(float)ecs->getNumOfEstimatedCalls();3771float numCallsFactor = (float)(avgMethodSize)/110.0f;37723773numCallsFactor = std::max(factor, 0.1f);37743775if (size > 100)3776{3777size = (int)((float)size * factor * numCallsFactor);3778if (size < 100) size = 100;3779}3780else3781{3782size = (int)((float)size * factor * numCallsFactor);3783}3784if (comp()->trace(OMR::inlining))3785heuristicTrace(tracer(), "WeighCallSite: Adjusted call-graph size for call node %p, from %d to %d\n", callsite->_callNode, origSize, size);3786}3787else if ((frequency2 > 0) && (frequency2 < veryColdBorderFrequency)) // luke-warm block3788{3789float factor = (float)frequency2 / (float)maxFrequency;3790//factor = std::max(factor, 0.1f);3791size = (int)((float)size / (factor*factor)); // make the size look bigger to inline less3792if (comp()->trace(OMR::inlining))3793heuristicTrace(tracer(), "WeighCallSite: Adjusted call-graph size for call node %p, from %d to %d\n", callsite->_callNode, origSize, size);3794}3795else if ((frequency2 >= 0) && (frequency2 < coldBorderFrequency)) // very cold block3796{3797//to avoid division by zero crash. Semantically freqs of 0 and 1 should be pretty close given maxFrequency of 10K3798int adjFrequency2 = frequency2 ? frequency2 : 1;3799float factor = (float)adjFrequency2 / (float)maxFrequency;3800//factor = std::max(factor, 0.1f);3801size = (int)((float)size / factor);380238033804if (comp()->trace(OMR::inlining))3805heuristicTrace(tracer(),"WeighCallSite: Adjusted call-graph size for call node %p, from %d to %d\n", callsite->_callNode, origSize, size);3806}3807else3808{3809if (comp()->trace(OMR::inlining))3810heuristicTrace(tracer(),"WeighCallSite: Not adjusted call-graph size for call node %p, size %d\n", callsite->_callNode, origSize);3811}3812}3813}38143815bool toInline = getPolicy()->tryToInline(calltarget, callStack, true);3816heuristicTrace(tracer(),"WeighCallSite: For Target %p node %p, size after size mangling %d",calltarget,calltarget->_myCallSite->_callNode,size);38173818if (!toInline && !forceInline(calltarget) && (size > _maxRecursiveCallByteCodeSizeEstimate || ecs->recursedTooDeep() == true))3819{3820if (isWarm(comp()))3821{3822if (comp()->isServerInlining())3823{3824if (callsite->_callNode->getInlinedSiteIndex() < 0) //Ensures setWarmCallGraphTooBig is only called for methods with inline index -1 (indexes >=0 can happen when inliner is called after inlining has already occured3825comp()->getCurrentMethod()->setWarmCallGraphTooBig (callsite->_callNode->getByteCodeInfo().getByteCodeIndex(), comp());3826else3827heuristicTrace(tracer(),"Not calling setWarmCallGraphTooBig on callNode %p because it is not from method being compiled bc index %d inlinedsiteindex %d",callsite->_callNode,callsite->_callNode->getByteCodeInfo().getByteCodeIndex(),callsite->_callNode->getInlinedSiteIndex());3828if (comp()->trace(OMR::inlining))3829heuristicTrace(tracer(),"inliner: Marked call as warm callee too big: %d > %d: %s\n", size, ecs->getSizeThreshold(), tracer()->traceSignature(calltarget->_calleeSymbol));3830}3831//printf("inliner: Marked call as warm callee too big: %d > %d: %s\n", nonRecursiveSize, sizeThreshold, calleeSymbol->signature(trMemory()));3832}3833tracer()->insertCounter(Callee_Too_Many_Bytecodes,calltarget->_myCallSite->_callNodeTreeTop);3834TR::Options::INLINE_calleeToDeep ++;3835if (comp()->trace(OMR::inlining))3836traceMsg(comp(), "inliner: size exceeds call graph size threshold: %d > %d: %s\n", size, _maxRecursiveCallByteCodeSizeEstimate, tracer()->traceSignature(calltarget->_calleeSymbol));38373838callsite->removecalltarget(k,tracer(),Exceeds_Size_Threshold);3839k--;3840continue;3841}3842}38433844if (comp()->getOption(TR_DisableNewInliningInfrastructure))3845calltarget->_isPartialInliningCandidate = false;38463847int32_t weight = size;3848int32_t origWeight = weight;38493850heuristicTrace(tracer(),"Beginning of Weight Calculation. Setting weight to %d",weight);385138523853if (!comp()->getOption(TR_DisableInlinerFanIn))3854{3855j9inlinerPolicy->adjustFanInSizeInWeighCallSite (weight,3856size,3857calltarget->_calleeSymbol->getResolvedMethod(),3858callsite->_callerResolvedMethod,3859callsite->_callNode->getByteCodeIndex());3860}38613862if (callStack->_inALoop)3863{3864weight >>= 2; // divide by 43865if(getPolicy()->aggressiveSmallAppOpts())3866weight >>=3;3867heuristicTrace(tracer(),"Setting weight to %d because call is in a loop.",weight);3868}3869else if (!callStack->_alwaysCalled)3870{3871if ( getPolicy()->aggressiveSmallAppOpts() && comp()->getMethodSymbol()->getRecognizedMethod() == TR::java_util_GregorianCalendar_computeFields)3872{3873TR::TreeTop *callNodeTreeTop = calltarget->_myCallSite->_callNodeTreeTop;3874int32_t adjustment = 5;3875if (callNodeTreeTop)3876{3877TR::Block * block = callNodeTreeTop->getEnclosingBlock();3878int32_t frequency = block->getFrequency();3879if(frequency > 1000)3880adjustment = 10;3881else3882adjustment = (frequency*10)/10000;3883}38843885adjustment = std::max(5, adjustment);3886if (adjustment == 0)3887adjustment = 5;3888weight = (weight * 10) / adjustment;3889}3890heuristicTrace(tracer(),"Setting weight to %d because call is not always called.",weight);3891}38923893int32_t weightBeforeLookingForBenefits = weight;38943895bool isLambdaFormGeneratedMethod = comp()->fej9()->isLambdaFormGeneratedMethod(calltarget->_calleeMethod);3896if ((calltarget->_calleeMethod->convertToMethod()->isArchetypeSpecimen() && calltarget->_calleeMethod->getMethodHandleLocation()) || isLambdaFormGeneratedMethod)3897{3898static char *methodHandleThunkWeightFactorStr = feGetEnv("TR_methodHandleThunkWeightFactor");3899static int32_t methodHandleThunkWeightFactor = methodHandleThunkWeightFactorStr? atoi(methodHandleThunkWeightFactorStr) : 10;3900// MethodHandle thunks benefit a great deal from inlining so let's encourage them.3901weight /= methodHandleThunkWeightFactor;3902heuristicTrace(tracer(),"Setting weight to %d because callee is MethodHandle thunk.",weight);3903}390439053906TR_LinkHead<TR_ParameterMapping> map;3907if(!((TR_J9InlinerPolicy *)getPolicy())->validateArguments(calltarget,map)) //passing map by reference3908{3909continue; // arguments are not valid for this calltarget3910}39113912weight = applyArgumentHeuristics(map,weight, calltarget);39133914if (calltarget->_calleeMethod->isDAAWrapperMethod())3915{3916weight = 1;3917heuristicTrace(tracer(),"Setting DAA wrapper methods weights to minimum(%d).", weight);3918}39193920#ifdef ENABLE_SPMD_SIMD3921if (/*calltarget->_calleeSymbol->getRecognizedMethod() == TR::com_ibm_simt_SPMDKernel_execute ||*/3922calltarget->_calleeSymbol->getRecognizedMethod() == TR::com_ibm_simt_SPMDKernel_kernel3923)3924{3925weight = 1;3926traceMsg(comp(), "Setting SIMD kernel methods weights to minimum(%d) node %p.", weight, callsite->_callNode);3927}3928#endif39293930if (weightBeforeLookingForBenefits != weight)3931wouldBenefitFromInlining = true;39323933if (possiblyVeryHotLargeCallee && !wouldBenefitFromInlining)3934{3935// Increase the possibility of callee reaching scorching with profiling done in it since3936// it is possible we collect more useful profile data if it is not inlined3937// (since the profiling budget for the caller might get exhausted on some3938// other long running loop earlier than the place where the callee is inlined)3939// Only do this if the current method is very hot (so callee will likely be very hot if it3940// is large) and there are no obvious benefits from inlining the large callee.3941// Important in _228_jack since we do not want to inline the Move method into getNextTokenFromStream3942//39433944if ( getPolicy()->aggressiveSmallAppOpts() && comp()->getMethodSymbol()->getRecognizedMethod() == TR::java_util_GregorianCalendar_computeFields)3945{39463947TR::TreeTop *callNodeTreeTop = calltarget->_myCallSite->_callNodeTreeTop;3948int32_t adjustment = 5;3949if (callNodeTreeTop)3950{3951TR::Block * block = callNodeTreeTop->getEnclosingBlock();3952int32_t frequency = block->getFrequency();3953if(frequency > 1000)3954adjustment = 10;3955else3956adjustment = (frequency*10)/10000;3957}39583959adjustment = std::max(5, adjustment);3960if (adjustment == 0)3961adjustment = 5;3962weight = (weight * 10) / adjustment;39633964}3965else3966weight <<= 1;3967heuristicTrace(tracer(),"Setting weight to %d because method is possibly a very hot and large callee", weight);3968}39693970if (ecs->isLeaf())3971{3972weight -= 4;3973heuristicTrace(tracer(),"Setting weight to %d because method is a leaf method", weight);3974}39753976static char *xyz = feGetEnv("TR_MaxWeightReduction");3977uint32_t maxWeightReduction = xyz ? atoi(xyz) : 8;3978if (weight < (origWeight/maxWeightReduction))3979{3980weight = origWeight/8;3981heuristicTrace(tracer(),"Setting weight to %d because weight is less than originalWeight/8", weight);3982}398339843985float callGraphAdjustedWeight = 0.0f;3986int32_t callGraphWeight = -1;3987TR_ValueProfileInfoManager * profileManager = TR_ValueProfileInfoManager::get(comp());3988bool callGraphEnabled = profileManager->isCallGraphProfilingEnabled(comp()) && !_EDODisableInlinedProfilingInfo;39893990if (callGraphEnabled)3991callGraphAdjustedWeight = profileManager->getAdjustedInliningWeight(calltarget->_myCallSite->_callNode, weight, comp());39923993//There's (almost) no way to get out of adding the call site to the list of call sites.3994//Exceptions: 1) you blow your budget3995// 2) reflection3996// We only WeighCallSite() for the original method. So we will only have a list of call sites of top level methods.39973998calltarget->_size = size;3999calltarget->_weight = (int32_t)(weight/calltarget->_frequencyAdjustment);4000calltarget->_callGraphAdjustedWeight = callGraphAdjustedWeight/calltarget->_frequencyAdjustment;40014002heuristicTrace(tracer(),"WeighCallSite: Adding call target %p node %p with calleeSymbol = %p to list of call sites with guard %p kind = %d"4003"type = %d weight = %d (adjusted by frequencyAdjustment of %d) callGraphAdjustedWeight = %d",4004calltarget,calltarget->_myCallSite->_callNode,calltarget->_calleeSymbol,calltarget->_guard,calltarget->_guard->_kind,4005calltarget->_guard->_type,calltarget->_weight,calltarget->_frequencyAdjustment, calltarget->_callGraphAdjustedWeight);40064007TR_CallTarget *calltargetiterator = _callTargets.getFirst(), * prevTarget = 0;4008bool dontinsert = false;4009if (dontAddCalls == true)4010{4011// printf("Would have inserted bogus call to list from walkcallsites\n");fflush(stdout);4012dontinsert=true;4013}4014for (; calltargetiterator; prevTarget = calltargetiterator, calltargetiterator=calltargetiterator->getNext())4015if (callGraphEnabled)4016{4017if (callGraphAdjustedWeight < calltargetiterator->_callGraphAdjustedWeight)4018{4019_callTargets.insertAfter(prevTarget, calltarget);4020dontinsert=true;4021break;4022}4023else if ((callGraphAdjustedWeight == calltargetiterator->_callGraphAdjustedWeight) &&4024(weight < calltargetiterator->_weight))4025{4026_callTargets.insertAfter(prevTarget, calltarget);4027//return;4028dontinsert=true;4029break;4030}4031}4032else if (weight < calltargetiterator->_weight)4033{4034_callTargets.insertAfter(prevTarget, calltarget);4035//return;4036dontinsert=true;4037break;4038}4039if(!dontinsert)4040_callTargets.insertAfter(prevTarget, calltarget);4041} //end for loop over call targets404240434044heuristicTrace(tracer(),"^^^ Done Weighing of all targets in CallSite %p callnode %p\n",callsite, callsite->_callNode);4045}40464047bool TR_MultipleCallTargetInliner::inlineSubCallGraph(TR_CallTarget* calltarget)4048{4049TR_J9InlinerPolicy *j9inlinerPolicy = (TR_J9InlinerPolicy *) getPolicy();4050/*4051* keep the target if it meets either of the following condition:4052* 1. It's a JSR292 related method. This condition allows inlining method handle thunk chain without inlining the leaf java method.4053* 2. It's force inline target4054* 3. It's a method deemed always worth inlining, e.g. an Unsafe method4055* which would otherwise generate a j2i transition.4056*/4057TR::Node *callNode = NULL; // no call node has been generated yet4058if (j9inlinerPolicy->isJSR292Method(calltarget->_calleeMethod)4059|| forceInline(calltarget)4060|| j9inlinerPolicy->alwaysWorthInlining(calltarget->_calleeMethod, callNode))4061{4062for (TR_CallSite* callsite = calltarget->_myCallees.getFirst(); callsite ; callsite = callsite->getNext())4063{4064for (int32_t i = 0 ; i < callsite->numTargets() ; i++)4065inlineSubCallGraph(callsite->getTarget(i));4066}4067return true;4068}40694070calltarget->_myCallSite->removecalltarget(calltarget, tracer(), Trimmed_List_of_Callees);4071return false;4072}40734074void TR_MultipleCallTargetInliner::processChoppedOffCallTargets(TR_CallTarget *lastTargetToInline, TR_CallTarget* firstChoppedOffcalltarget, int estimatedNumberOfNodes)4075{4076if (firstChoppedOffcalltarget)4077{4078TR_CallTarget * calltarget = firstChoppedOffcalltarget;4079for (; calltarget; calltarget = calltarget->getNext())4080{4081if (inlineSubCallGraph(calltarget))4082{4083generateNodeEstimate myEstimate;4084recursivelyWalkCallTargetAndPerformAction(calltarget, myEstimate);4085estimatedNumberOfNodes += myEstimate.getNodeEstimate();4086/*4087* ForceInline targets and JSR292 methods should always be inlined regarless of budget. However, with4088* inlining methodhandle chain in normal inlining, the number of nodes can be tremendous resulting in4089* compilations, especially those with higher opt level, eating up too much CPU time. The heuristic here4090* is added to prevent compilations consuming too much CPU.4091*/4092static bool dontAbortCompilationEvenWithLargeInliningNodesEstimation = feGetEnv("TR_DontAbortCompilationEvenWithLargeInliningNodesEstimation") ? true: false;4093if (!dontAbortCompilationEvenWithLargeInliningNodesEstimation && estimatedNumberOfNodes > 50000 && comp()->getMethodHotness() >= hot)4094comp()->failCompilation<TR::ExcessiveComplexity>("too many nodes if forced inlining targets are included");40954096if (lastTargetToInline)4097lastTargetToInline->setNext(calltarget);4098else4099_callTargets.setFirst(calltarget);4100lastTargetToInline = calltarget;4101}4102}4103}41044105if (lastTargetToInline)4106lastTargetToInline->setNext(NULL);4107else _callTargets.setFirst(NULL);4108}41094110//Note, this function is shared by all FE's. If you are changing the heuristic for your FE only, you need to push this method into the various FE's FEInliner.cpp file.4111int32_t TR_MultipleCallTargetInliner::scaleSizeBasedOnBlockFrequency(int32_t bytecodeSize, int32_t frequency, int32_t borderFrequency, TR_ResolvedMethod * calleeResolvedMethod, TR::Node *callNode, int32_t coldBorderFrequency)4112{4113int32_t maxFrequency = MAX_BLOCK_COUNT + MAX_COLD_BLOCK_COUNT;41144115bool largeCompiledCallee = !comp()->getOption(TR_InlineVeryLargeCompiledMethods) &&4116isLargeCompiledMethod(calleeResolvedMethod, bytecodeSize, frequency);4117if (largeCompiledCallee)4118{4119bytecodeSize = bytecodeSize * TR::Options::_inlinerVeryLargeCompiledMethodAdjustFactor;4120}4121else if (frequency > borderFrequency)4122{4123int32_t oldSize = 0;4124if (comp()->trace(OMR::inlining))4125oldSize = bytecodeSize;41264127float factor = (float)(maxFrequency-frequency)/(float)maxFrequency;4128factor = getScalingFactor(factor);412941304131bytecodeSize = (int32_t)((float)bytecodeSize * factor);4132if (bytecodeSize < 10) bytecodeSize = 10;41334134heuristicTrace(tracer(),"exceedsSizeThreshold (mct): Scaled down size for call from %d to %d", oldSize, bytecodeSize);4135}4136else if (frequency < coldBorderFrequency)4137{4138int32_t oldSize = 0;4139if (comp()->trace(OMR::inlining))4140oldSize = bytecodeSize;41414142//to avoid division by zero crash. Semantically freqs of 0 and 1 should be pretty close given maxFrequency of 10K4143int adjFrequency = frequency ? frequency : 1;41444145float factor = (float)adjFrequency / (float)maxFrequency;4146float weight = (float)bytecodeSize / (factor*factor);4147bytecodeSize = (weight > 0x7fffffff) ? 0x7fffffff : ((int32_t)weight);41484149heuristicTrace(tracer(),"exceedsSizeThreshold: Scaled up size for call from %d to %d", oldSize, bytecodeSize);4150}4151return bytecodeSize;4152}415341544155bool TR_MultipleCallTargetInliner::isLargeCompiledMethod(TR_ResolvedMethod *calleeResolvedMethod, int32_t bytecodeSize, int32_t callerBlockFrequency)4156{4157TR_OpaqueMethodBlock* methodCallee = calleeResolvedMethod->getPersistentIdentifier();4158if (!calleeResolvedMethod->isInterpreted())4159{4160TR_PersistentJittedBodyInfo * bodyInfo = ((TR_ResolvedJ9Method*) calleeResolvedMethod)->getExistingJittedBodyInfo();4161if ((comp()->getMethodHotness() <= warm))4162{4163if (bodyInfo &&4164(bodyInfo->getHotness() >= warm))4165{4166// hot and scorching bodies should never be inlined to warm or cooler bodies4167if (bodyInfo->getHotness() >= hot)4168{4169return true;4170}41714172// Allow inlining of big methods into high frequency blocks4173if (callerBlockFrequency > comp()->getOptions()->getLargeCompiledMethodExemptionFreqCutoff())4174return false;41754176int32_t veryLargeCompiledMethodThreshold = comp()->getOptions()->getInlinerVeryLargeCompiledMethodThreshold();4177int32_t veryLargeCompiledMethodFaninThreshold = comp()->getOptions()->getInlinerVeryLargeCompiledMethodFaninThreshold();4178// Subdue inliner in low frequency blocks4179if (callerBlockFrequency > 0)4180{4181if ((2 * callerBlockFrequency) < comp()->getOptions()->getLargeCompiledMethodExemptionFreqCutoff())4182{4183veryLargeCompiledMethodThreshold = 100;4184veryLargeCompiledMethodFaninThreshold = 0;4185}4186}41874188uint32_t numCallers = 0, totalWeight = 0;4189((TR_ResolvedJ9Method *) calleeResolvedMethod)->getFaninInfo(&numCallers, &totalWeight);4190if ((numCallers > veryLargeCompiledMethodFaninThreshold) &&4191(bytecodeSize > veryLargeCompiledMethodThreshold))4192{4193return true;4194}4195}4196}4197else if (comp()->getMethodHotness() < scorching)4198{4199// scorching compiled methods should not be inlined in compiles below scorching4200// unless we are preparing to upgrade the compile and need profiling info4201if (bodyInfo &&4202(bodyInfo->getHotness() >= scorching) &&4203!(comp()->isProfilingCompilation() && comp()->getMethodHotness() == veryHot))4204{4205return true;4206}4207}4208}4209return false;4210}421142124213bool4214TR_MultipleCallTargetInliner::exceedsSizeThreshold(TR_CallSite *callSite, int bytecodeSize, TR::Block *block, TR_ByteCodeInfo & bcInfo, int32_t numLocals, TR_ResolvedMethod * callerResolvedMethod, TR_ResolvedMethod * calleeResolvedMethod,TR::Node *callNode, bool allConsts)4215{4216if (alwaysWorthInlining(calleeResolvedMethod, callNode))4217return false;42184219TR_J9InlinerPolicy *j9InlinerPolicy = (TR_J9InlinerPolicy *)getPolicy();4220static char *polymorphicCalleeSizeThresholdStr = feGetEnv("TR_InlinerPolymorphicConservatismCalleeSize");4221int polymorphicCalleeSizeThreshold = polymorphicCalleeSizeThresholdStr ? atoi(polymorphicCalleeSizeThresholdStr) : 10;4222static char *polymorphicRootSizeThresholdStr = feGetEnv("TR_InlinerPolymorphicConservatismRootSize");4223int polymorphicRootSizeThreshold = polymorphicRootSizeThresholdStr ? atoi(polymorphicRootSizeThresholdStr) : 30;4224static char *trustedInterfacePattern = feGetEnv("TR_TrustedPolymorphicInterfaces");4225static TR::SimpleRegex *trustedInterfaceRegex = trustedInterfacePattern ? TR::SimpleRegex::create(trustedInterfacePattern) : NULL;4226// we need to be conservative about inlining potentially highly polymorphic interface calls for4227// functional frameworks like scala - we limit this to hot and above4228// if the callsite is highly polymorphic but the following conditions are meet, still inline the callee4229// 1. the compiling method is scorching4230// 2. the callee is scorching OR queued for veryhot/scorching compile4231int32_t outterMethodSize = getJ9InitialBytecodeSize(callSite->_callerResolvedMethod, 0, comp());4232if (comp()->getMethodHotness() > warm && callSite->isInterface()4233&& bytecodeSize > polymorphicCalleeSizeThreshold4234&& outterMethodSize > polymorphicRootSizeThreshold4235&& ((bytecodeSize * 100) / outterMethodSize) < 64236&& (!callSite->_ecsPrexArgInfo || !callSite->_ecsPrexArgInfo->get(0) || !callSite->_ecsPrexArgInfo->get(0)->getClass())4237&& comp()->fej9()->maybeHighlyPolymorphic(comp(), callSite->_callerResolvedMethod, callSite->_cpIndex, callSite->_interfaceMethod, callSite->_receiverClass)4238&& (!trustedInterfaceRegex || !TR::SimpleRegex::match(trustedInterfaceRegex, callSite->_interfaceMethod->signature(trMemory()), false)))4239{4240TR_PersistentJittedBodyInfo *bodyInfo = NULL;4241if (!calleeResolvedMethod->isInterpretedForHeuristics() && !calleeResolvedMethod->isJITInternalNative())4242{4243bodyInfo = ((TR_ResolvedJ9Method*) calleeResolvedMethod)->getExistingJittedBodyInfo();4244}4245if (((!bodyInfo && !calleeResolvedMethod->isInterpretedForHeuristics() && !calleeResolvedMethod->isJITInternalNative()) //jitted method without bodyInfo must be scorching4246|| (bodyInfo && bodyInfo->getHotness() == scorching)4247|| comp()->fej9()->isQueuedForVeryHotOrScorching(calleeResolvedMethod, comp()))4248&& (comp()->getMethodHotness() == scorching))4249debugTrace(tracer(), "### inline this callee because the compiling method and callee are both scorching even though it's potentially highly polymorphic callsite initialCalleeSymbol = %s callerResolvedMethod = %s calleeResolvedMethod = %s\n",4250tracer()->traceSignature(callSite->_interfaceMethod), tracer()->traceSignature(callerResolvedMethod), tracer()->traceSignature(calleeResolvedMethod));4251else4252{4253debugTrace(tracer(), "### exceeding size threshold for potentially highly polymorphic callsite initialCalleeSymbol = %s callerResolvedMethod = %s calleeResolvedMethod = %s\n",4254tracer()->traceSignature(callSite->_interfaceMethod), tracer()->traceSignature(callerResolvedMethod), tracer()->traceSignature(calleeResolvedMethod));4255TR::DebugCounter::incStaticDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "inliner.highlyPolymorphicFail/(%s)/%s/(%s)/sizes=%d.%d", comp()->signature(), comp()->getHotnessName(comp()->getMethodHotness()), callSite->_interfaceMethod->signature(trMemory()), bytecodeSize, outterMethodSize));4256return true;4257}4258}42594260if (comp()->getMethodHotness() > warm && !comp()->isServerInlining())4261return TR_InlinerBase::exceedsSizeThreshold(callSite, bytecodeSize, block, bcInfo,numLocals,callerResolvedMethod,calleeResolvedMethod,callNode,allConsts);42624263heuristicTrace(tracer(),"### Checking multiple call target inliner sizeThreshold. bytecodeSize = %d, block = %p, numLocals = %p, callerResolvedMethod = %s,"4264" calleeResolvedMethod = %s opt server is %d methodHotness = %d warm = %d\n",4265bytecodeSize,block,numLocals,tracer()->traceSignature(callerResolvedMethod),tracer()->traceSignature(calleeResolvedMethod), comp()->isServerInlining(),comp()->getMethodHotness(), warm);42664267int32_t origbytecodeSize=bytecodeSize;4268bool isCold = false;4269int32_t frequency1 = 0, frequency2 = 0;427042714272// In the old days we used 2000,50 for optServer, 2500,1000 for noOptServer4273// Now we want to use 6000, 1500 for optServer42744275if (block)4276{4277int32_t borderFrequency;4278int32_t veryColdBorderFrequency;42794280getBorderFrequencies(borderFrequency, veryColdBorderFrequency, calleeResolvedMethod, callNode);428142824283// HACK: Get frequency from both sources, and use both. You're4284// only cold if you're cold according to both.42854286bool isLambdaFormGeneratedMethod = comp()->fej9()->isLambdaFormGeneratedMethod(callerResolvedMethod);4287// TODO: we should ignore frequency for thunk archetype, however, this require performance evaluation4288bool frequencyIsInaccurate = isLambdaFormGeneratedMethod;42894290frequency1 = comp()->convertNonDeterministicInput(comp()->fej9()->getIProfilerCallCount(bcInfo, comp()), MAX_BLOCK_COUNT + MAX_COLD_BLOCK_COUNT, randomGenerator(), 0);4291frequency2 = comp()->convertNonDeterministicInput(block->getFrequency(), MAX_BLOCK_COUNT + MAX_COLD_BLOCK_COUNT, randomGenerator(), 0);4292if (frequency1 > frequency2 && callerResolvedMethod->convertToMethod()->isArchetypeSpecimen())4293frequency2 = frequency1;42944295if ((frequency1 <= 0) && ((0 <= frequency2) && (frequency2 <= MAX_COLD_BLOCK_COUNT)) &&4296!alwaysWorthInlining(calleeResolvedMethod, callNode) &&4297!frequencyIsInaccurate)4298{4299isCold = true;4300}43014302debugTrace(tracer(), "exceedsSizeThreshold: Call with block_%d has frequency1 %d frequency2 %d ", block->getNumber(), frequency1, frequency2);43034304if (allowBiggerMethods() &&4305!comp()->getMethodSymbol()->doJSR292PerfTweaks() &&4306calleeResolvedMethod &&4307!frequencyIsInaccurate &&4308!j9InlinerPolicy->isInlineableJNI(calleeResolvedMethod, callNode))4309{4310bytecodeSize = scaleSizeBasedOnBlockFrequency(bytecodeSize,frequency2,borderFrequency, calleeResolvedMethod,callNode,veryColdBorderFrequency);4311}4312else if (getPolicy()->aggressiveSmallAppOpts())4313{4314traceMsg(comp(), "Reached new code 2\n");4315int32_t blockNestingDepth = 1;4316if (_isInLoop)4317{4318char *tmptmp =0;4319if (calleeResolvedMethod)4320tmptmp = TR::Compiler->cls.classSignature(comp(), calleeResolvedMethod->containingClass(), trMemory());4321bool doit = false;43224323if (j9InlinerPolicy->aggressivelyInlineInLoops())4324{4325doit = true;4326}43274328if (doit && calleeResolvedMethod && !strcmp(tmptmp,"Ljava/math/BigDecimal;"))4329{4330traceMsg(comp(), "Reached code for block nesting depth %d\n", blockNestingDepth);4331if ((_isInLoop || (blockNestingDepth > 1)) &&4332(bytecodeSize > 10))4333{4334if (comp()->trace(OMR::inlining))4335heuristicTrace(tracer(),"Exceeds Size Threshold: Scaled down size for call block %d from %d to %d\n", block->getNumber(), bytecodeSize, 10);4336bytecodeSize = 10;4337}4338}4339else4340heuristicTrace(tracer(),"Omitting Big Decimal method from size readjustment, calleeResolvedMethod = %p tmptmp = %s",calleeResolvedMethod, tmptmp);4341}4342}4343}43444345// reduce size if your args are consts4346if (callNode)4347{4348heuristicTrace(tracer(),"In ExceedsSizeThreshold. Reducing size from %d",bytecodeSize);43494350int32_t originalbcSize = bytecodeSize;4351uint32_t numArgs = callNode->getNumChildren();4352bool allconstsfromCallNode = true;43534354uint32_t i = callNode->getFirstArgumentIndex();43554356if( callNode->getOpCode().isCall() &&4357!callNode->getSymbolReference()->isUnresolved() &&4358callNode->getSymbolReference()->getSymbol()->getMethodSymbol() &&4359!callNode->getSymbolReference()->getSymbol()->castToMethodSymbol()->isHelper() &&4360!callNode->getSymbolReference()->getSymbol()->castToMethodSymbol()->isSystemLinkageDispatch() &&4361!callNode->getSymbolReference()->getSymbol()->castToMethodSymbol()->isStatic() )4362++i;43634364for (; i < numArgs; ++i)4365{43664367// printf("callNode = %p\n");fflush(stdout);4368// printf("callNode->getOpCode().isCall() = %p\n");fflush(stdout);4369// printf("callNode->getSymbolReference() = %p\n");fflush(stdout);4370// pr43714372TR::Node * arg = callNode->getChild(i);4373if (arg->getOpCode().isLoadConst())4374{4375heuristicTrace(tracer(),"Node %p is load const\n",arg);4376bytecodeSize = bytecodeSize - (bytecodeSize/10);4377}4378else if (arg->getOpCodeValue() == TR::aload && arg->getSymbolReference()->getSymbol()->isConstObjectRef())4379{4380heuristicTrace(tracer(),"Node %p is aload const\n",arg);4381bytecodeSize = bytecodeSize - (bytecodeSize/10);4382}4383else4384{4385heuristicTrace(tracer(),"Node %p is not const\n",arg);4386allconstsfromCallNode = false;4387}4388}438943904391if (!allconstsfromCallNode)4392bytecodeSize = originalbcSize;43934394else if (bytecodeSize < originalbcSize && originalbcSize > 100)4395{4396/*4397char tmpian[1024];4398comp()->fej9()->sampleSignature(calleeResolvedMethod->getPersistentIdentifier(), tmpian, 1024, trMemory());4399printf("R size of bc %d to %d meth %s comp %s\n",originalbcSize,bytecodeSize,tmpian,comp()->signature());4400fflush(stdout);4401*/4402}44034404heuristicTrace(tracer()," to %d because of const arguments", bytecodeSize);44054406/* if ( bytecodeSize != originalbcSize )4407{4408char tmpian[1024];4409comp()->fej9()->sampleSignature(calleeResolvedMethod->getPersistentIdentifier(), tmpian, 1024, trMemory());4410printf("R size of bc %d to %d meth %s comp %s\n",originalbcSize,bytecodeSize,tmpian,comp()->signature());4411fflush(stdout);4412}4413*/4414}4415else if (allConsts)4416{44174418int32_t originalbcSize=bytecodeSize;4419heuristicTrace(tracer(),"In ExceedsSizeThreshold. Reducing size from %d",bytecodeSize);44204421int32_t numArgs = calleeResolvedMethod->numberOfExplicitParameters();4422for (int32_t i=0 ; i < numArgs; ++i)4423{4424bytecodeSize = bytecodeSize - (bytecodeSize/10);4425}44264427heuristicTrace(tracer()," to %d because of const arguments",bytecodeSize);44284429/*4430if (bytecodeSize < originalbcSize && originalbcSize > 100)4431{4432char tmpian[1024];4433comp()->fe()->sampleSignature(calleeResolvedMethod->getPersistentIdentifier(), tmpian, 1024, trMemory());4434printf("R size of bc %d to %d meth %s comp %s\n",originalbcSize,bytecodeSize,tmpian,comp()->signature());4435fflush(stdout);4436}4437*/4438}44394440static const char *qq;4441static uint32_t min_size = ( qq = feGetEnv("TR_Min_FanIn_Size")) ? atoi(qq) : MIN_FAN_IN_SIZE;4442static const char *q;4443static uint32_t multiplier = ( q = feGetEnv("TR_SizeMultiplier")) ? atoi (q) : SIZE_MULTIPLIER;4444uint32_t calculatedSize = bytecodeSize; //(bytecodeSize - MIN_FAN_IN_SIZE);44454446if (!comp()->getOption(TR_DisableInlinerFanIn)) // TODO: make the default for everybody4447{4448// In JIT, having low caller information is equivalent to lack of information. We want to exclude only cases where we know we have alot of fan-in4449if (j9InlinerPolicy->adjustFanInSizeInExceedsSizeThreshold(bytecodeSize, calculatedSize, calleeResolvedMethod, callerResolvedMethod, bcInfo.getByteCodeIndex()))4450{4451return true;4452}4453}4454// else4455// {4456// calculatedSize=bytecodeSize;4457// }445844594460if (isCold && (bytecodeSize > _methodInColdBlockByteCodeSizeThreshold))4461{4462if (block)4463{4464TR::DebugCounter::prependDebugCounter(comp(), "inliner.callSites/failed/coldCallee/tooManyBytecodes", block->getFirstRealTreeTop());4465TR::DebugCounter::prependDebugCounter(comp(), "inliner.callSites/failed/coldCallee/tooManyBytecodes:#bytecodeSize", block->getFirstRealTreeTop(), bytecodeSize);4466TR::DebugCounter::prependDebugCounter(comp(), "inliner.callSites/failed/coldCallee/tooManyBytecodes:#excess", block->getFirstRealTreeTop(), bytecodeSize-_methodInColdBlockByteCodeSizeThreshold);4467}4468heuristicTrace(tracer(),"### Exceeds Size Threshold because call is cold and has a bytecodeSize %d > _methodInColdBlockByteCodeSizeThreshold %d", bytecodeSize,_methodInColdBlockByteCodeSizeThreshold);4469return true; // exceeds size threshold4470}44714472if(bytecodeSize > _methodInWarmBlockByteCodeSizeThreshold || calculatedSize > _methodInWarmBlockByteCodeSizeThreshold*multiplier)4473{4474if (block)4475{4476TR::DebugCounter::prependDebugCounter(comp(), "inliner.callSites/failed/warmCallee/tooManyBytecodes", block->getFirstRealTreeTop());4477TR::DebugCounter::prependDebugCounter(comp(), "inliner.callSites/failed/warmCallee/tooManyBytecodes:#bytecodeSize", block->getFirstRealTreeTop(), bytecodeSize);4478TR::DebugCounter::prependDebugCounter(comp(), "inliner.callSites/failed/warmCallee/tooManyBytecodes:#excess", block->getFirstRealTreeTop(), bytecodeSize - _methodInWarmBlockByteCodeSizeThreshold);4479}44804481if( bytecodeSize <= _methodInWarmBlockByteCodeSizeThreshold )4482{4483heuristicTrace(tracer(),"### Exceeds Size Threshold because calculatedSize %d > _methodInWarmBlockByteCodeSizeThreshold*multiplier %d (excessive Fan In)",calculatedSize,_methodInWarmBlockByteCodeSizeThreshold*multiplier);44844485static const char *r = feGetEnv("TR_PrintFanIn");4486if(r)4487{4488char calleeName2[1024];448944904491printf("Method %p %s excluded because it has fan in ratio of %f threshold = %d size = %d original = %d.\n",4492calleeResolvedMethod,4493comp()->fej9()->sampleSignature(calleeResolvedMethod->getPersistentIdentifier(), calleeName2, 1024, comp()->trMemory()),4494(float)calculatedSize/(float) bytecodeSize,_methodInWarmBlockByteCodeSizeThreshold*multiplier,calculatedSize,bytecodeSize);44954496}4497}4498else4499heuristicTrace(tracer(),"### Exceeds Size Threshold because bytecodeSize %d > _methodInWarmBlockByteCodeSizeThreshold %d",bytecodeSize,_methodInWarmBlockByteCodeSizeThreshold);45004501return true; // Exceeds size threshold4502}45034504if (isWarm(comp()))4505{4506if (OWNING_METHOD_MAY_NOT_BE_THE_CALLER && calleeResolvedMethod->owningMethodDoesntMatter())4507{4508// callerResolvedMethod may not correspond to the caller listed in bcInfo, so it's4509// not safe to call isWarmCallGraphTooBig.4510}4511else if (comp()->isServerInlining() &&4512!alwaysWorthInlining(calleeResolvedMethod, NULL) &&4513callerResolvedMethod->isWarmCallGraphTooBig(bcInfo.getByteCodeIndex(), comp()) &&4514!isHot(comp()))4515{4516heuristicTrace(tracer(),"### Avoiding estimation (even though size is reasonable) of call %s.(Exceeding Size Threshold)", tracer()->traceSignature(calleeResolvedMethod));4517return true;4518}4519}45204521heuristicTrace(tracer(),"### Did not exceed size threshold, bytecodeSize %d <= inlineThreshold %d",bytecodeSize, _methodInWarmBlockByteCodeSizeThreshold);45224523// Does not exceed size threshold4524return false;4525}45264527bool TR_J9InlinerPolicy::canInlineMethodWhileInstrumenting(TR_ResolvedMethod *method)4528{4529if ((TR::Compiler->vm.isSelectiveMethodEnterExitEnabled(comp()) && !comp()->fej9()->methodsCanBeInlinedEvenIfEventHooksEnabled(comp())) ||4530(comp()->fej9()->isAnyMethodTracingEnabled(method->getPersistentIdentifier()) &&4531!comp()->fej9()->traceableMethodsCanBeInlined()))4532return false;4533else return true;4534}45354536bool TR_J9InlinerPolicy::shouldRemoveDifferingTargets(TR::Node *callNode)4537{4538if (!OMR_InlinerPolicy::shouldRemoveDifferingTargets(callNode))4539return false;45404541TR::RecognizedMethod rm =4542callNode->getSymbol()->castToMethodSymbol()->getRecognizedMethod();45434544return rm != TR::java_lang_invoke_MethodHandle_invokeBasic;4545}45464547void4548TR_J9InlinerUtil::refineInlineGuard(TR::Node *callNode, TR::Block *&block1, TR::Block *&block2,4549bool &appendTestToBlock1, TR::ResolvedMethodSymbol * callerSymbol, TR::TreeTop *cursorTree,4550TR::TreeTop *&virtualGuard, TR::Block *block4)4551{4552TR::CFG * callerCFG = callerSymbol->getFlowGraph();4553TR_PrexArgInfo *argInfo = comp()->getCurrentInlinedCallArgInfo();4554if (argInfo)4555{4556if (comp()->usesPreexistence()) // Mark the preexistent arguments (maybe redundant if VP has already done that and provided the info in argInfo)4557{4558int32_t firstArgIndex = callNode->getFirstArgumentIndex();4559for (int32_t c = callNode->getNumChildren() -1; c >= firstArgIndex; c--)4560{4561TR::Node *argument = callNode->getChild(c);4562TR_PrexArgument *p = argInfo->get(c - firstArgIndex);4563if (p && p->usedProfiledInfo())4564{4565TR_OpaqueClassBlock *pc = p->getFixedProfiledClass();4566if (pc)4567{4568//printf("Creating new guards in method %s caller %s callee %s\n", comp()->signature(), callerSymbol->getResolvedMethod()->signature(trMemory()), calleeSymbol->getResolvedMethod()->signature(trMemory()));4569//fflush(stdout);457045714572TR::Block *origBlock1 = block1;4573TR::Block *newBlock = block1;4574TR::Block *newBlock2 = TR::Block::createEmptyBlock(callNode, comp(), block1->getFrequency());4575callerCFG->addNode(newBlock2);4576if (!appendTestToBlock1)4577{4578newBlock = TR::Block::createEmptyBlock(callNode, comp());4579callerCFG->addNode(newBlock);4580callerCFG->addEdge(block1, newBlock);4581callerCFG->addEdge(newBlock, block2);4582//callerCFG->addEdge(newBlock, newBlock2); //block4);4583callerCFG->copyExceptionSuccessors(block1, newBlock);4584callerCFG->removeEdge(block1, block2);4585}45864587TR::SymbolReferenceTable *symRefTab = comp()->getSymRefTab();45884589TR::Node * aconstNode = TR::Node::aconst(callNode, (uintptr_t)pc);4590aconstNode->setIsClassPointerConstant(true);45914592TR::Node *guard = NULL;4593TR::DataType dataType = argument->getDataType();4594TR::SymbolReference *newSymbolReference = comp()->getSymRefTab()->createTemporary(callerSymbol, dataType);45954596TR::Node *storeNode = TR::Node::createWithSymRef(comp()->il.opCodeForDirectStore(argument->getDataType()), 1, 1, argument, newSymbolReference);4597TR::TreeTop *storeTree = TR::TreeTop::create(comp(), storeNode);4598TR::TreeTop *nextTree = cursorTree->getNextTreeTop();45994600cursorTree->join(storeTree);4601storeTree->join(nextTree);4602cursorTree = storeTree;46034604TR::Node * aconstNullNode = TR::Node::create(callNode, TR::aconst, 0);4605TR::Node * nullcmp = TR::Node::createWithSymRef(argument, comp()->il.opCodeForDirectLoad(argument->getDataType()), 0, newSymbolReference);4606guard = TR::Node::createif(TR::ifacmpeq, nullcmp, aconstNullNode, block2->getEntry());46074608TR::TreeTop *newTreeTop = newBlock->append(TR::TreeTop::create(comp(), guard));4609if (!appendTestToBlock1)4610{4611newBlock->setDoNotProfile();4612block1->getExit()->join(newBlock->getEntry());4613newBlock->getExit()->join(block2->getEntry());4614}4615else4616virtualGuard = newTreeTop;46174618block1 = newBlock;4619block2 = block1->getNextBlock();4620//appendTestToBlock1 = false;46214622newBlock = newBlock2;4623callerCFG->addEdge(block1, newBlock);4624callerCFG->addEdge(newBlock, block2);4625callerCFG->addEdge(newBlock, block4);4626if (appendTestToBlock1)4627callerCFG->removeEdge(origBlock1, block4);4628callerCFG->copyExceptionSuccessors(block1, newBlock);4629// callerCFG->removeEdge(block1, block2);46304631TR::Node * vft = TR::Node::createWithSymRef(TR::aloadi, 1, 1, TR::Node::createWithSymRef(argument, comp()->il.opCodeForDirectLoad(argument->getDataType()), 0, newSymbolReference), symRefTab->findOrCreateVftSymbolRef());4632guard = TR::Node::createif(TR::ifacmpne, vft, aconstNode, block4->getEntry());46334634//argument->recursivelyDecReferenceCount();4635//callNode->setAndIncChild(c, TR::Node::create(comp()->il.opCodeForDirectLoad(argument->getDataType()), 0, newSymbolReference));46364637newTreeTop = newBlock->append(TR::TreeTop::create(comp(), guard));4638//if (!appendTestToBlock1)4639{4640newBlock->setDoNotProfile();4641block1->getExit()->join(newBlock->getEntry());4642newBlock->getExit()->join(block2->getEntry());4643}4644//else4645// virtualGuard = newTreeTop;46464647block1 = newBlock;4648block2 = block1->getNextBlock();4649appendTestToBlock1 = false;4650}4651}4652}4653}4654}4655}46564657void4658TR_J9InlinerUtil::refineInliningThresholds(TR::Compilation *comp, int32_t &callerWeightLimit, int32_t &maxRecursiveCallByteCodeSizeEstimate, int32_t &methodByteCodeSizeThreshold, int32_t &methodInWarmBlockByteCodeSizeThreshold, int32_t &methodInColdBlockByteCodeSizeThreshold, int32_t &nodeCountThreshold, int32_t size)4659{4660comp->fej9()->setInlineThresholds(comp, callerWeightLimit, maxRecursiveCallByteCodeSizeEstimate, methodByteCodeSizeThreshold,4661methodInWarmBlockByteCodeSizeThreshold, methodInColdBlockByteCodeSizeThreshold, nodeCountThreshold, size);4662}46634664bool4665TR_J9InlinerPolicy::doCorrectnessAndSizeChecksForInlineCallTarget(TR_CallStack *callStack, TR_CallTarget *calltarget, bool inlinefromgraph, TR_PrexArgInfo *argInfo)4666{4667// I think it would be a good idea to dump the list of Call Targets before doing the first inlineCallTarget.4668// You could get creative in your dumps: calltargets in order, calltargets by callsite, etc.46694670TR_LinkHead<TR_ParameterMapping> map;4671if (!validateArguments(calltarget, map))4672{4673TR_ASSERT(comp()->fej9()->canAllowDifferingNumberOrTypesOfArgsAndParmsInInliner(), "Error, call target has a parameter mapping issue.");46744675return false;4676}467746784679debugTrace(tracer(),"bool inlinecallTarget: calltarget %p calltarget->mycallsite %p calltarget->alreadyInlined = %d inlinefromgraph = %d currentNumberOfNodes = %d",calltarget,calltarget->_myCallSite,calltarget->_alreadyInlined, inlinefromgraph, _inliner->getCurrentNumberOfNodes());46804681TR_ASSERT(!(calltarget->_alreadyInlined && calltarget->_myCallSite->_callNode->isTheVirtualCallNodeForAGuardedInlinedCall()), "inlineCallTarget: trying to inline the virtual call node for a guarded inline call that's already been inlined!");4682int32_t nodeCount = _inliner->getCurrentNumberOfNodes();46834684int32_t sitesSize = (int32_t)(comp()->getNumInlinedCallSites());46854686if (sitesSize >= inliner()->getMaxInliningCallSites() && !inliner()->forceInline(calltarget))4687{4688tracer()->insertCounter(Exceeded_Caller_SiteSize,calltarget->_myCallSite->_callNodeTreeTop);4689if (comp()->trace(OMR::inlining))4690traceMsg(comp(), "inliner: failed: Caller has too many call sites %s\n", tracer()->traceSignature(calltarget->_calleeSymbol));4691return false;4692}46934694bool ignoreThisSmallMethod = getInitialBytecodeSize(calltarget->_calleeMethod, calltarget->_calleeSymbol, comp()) <= 20;4695//static int si, sj; ++sj;4696if (((_inliner->getNumAsyncChecks() > HIGH_LOOP_COUNT-5) || ((uint32_t)nodeCount > _inliner->getNodeCountThreshold())) && !_inliner->forceInline(calltarget) && !ignoreThisSmallMethod)4697{4698// getCurrentNumberOfNodes may be unreliable so we must recompute4699if (((uint32_t)(nodeCount = comp()->generateAccurateNodeCount()) > _inliner->getNodeCountThreshold()) || (_inliner->getNumAsyncChecks() > HIGH_LOOP_COUNT-5))4700{4701tracer()->insertCounter(Exceeded_Caller_Node_Budget,calltarget->_myCallSite->_callNodeTreeTop);47024703TR::Options::INLINE_calleeHasTooManyNodes++;4704TR::Options::INLINE_calleeHasTooManyNodesSum += nodeCount;4705if (comp()->trace(OMR::inlining))4706traceMsg(comp(), "inliner: failed: Caller has too many nodes %s while considering callee %s nodeCount = %d nodeCountThreshold = %d\n",comp()->signature(), tracer()->traceSignature(calltarget->_calleeSymbol),nodeCount,_inliner->getNodeCountThreshold());4707return false;4708}4709}47104711return true;4712}47134714bool4715TR_J9InlinerPolicy::validateArguments(TR_CallTarget *calltarget, TR_LinkHead<TR_ParameterMapping> &map)4716{4717calltarget->_calleeSymbol->setParameterList();47184719ListIterator<TR::ParameterSymbol> parms(&(calltarget->_calleeSymbol->getParameterList()));47204721int32_t numParms = calltarget->_calleeSymbol->getParameterList().getSize();4722int32_t numArgs = (int32_t) (calltarget->_myCallSite->_callNode->getNumChildren());47234724numArgs = numArgs - calltarget->_myCallSite->_callNode->getFirstArgumentIndex();47254726if (calltarget->_calleeSymbol->getResolvedMethod()->isJNINative() && calltarget->_calleeSymbol->getResolvedMethod()->isStatic() && calltarget->_myCallSite->_callNode->isPreparedForDirectJNI())4727numArgs--;47284729if (numArgs != numParms)4730{4731heuristicTrace(tracer(), "Number of Parameters %d and Arguments %d Differ. Removing Call Target for Safety's sake.", numParms, numArgs);4732calltarget->_myCallSite->removecalltarget(calltarget, tracer(), Cant_Match_Parms_to_Args);47334734TR_ASSERT(comp()->fej9()->canAllowDifferingNumberOrTypesOfArgsAndParmsInInliner() , "Can't match args to parms, arg number mismatch");47354736return false;4737}47384739inliner()->createParmMap(calltarget->_calleeSymbol, map);474047414742TR_ParameterMapping * parm = map.getFirst();4743int32_t argNodeIndex = calltarget->_myCallSite->_callNode->getFirstArgumentIndex();4744if (argNodeIndex == 0 && calltarget->_calleeSymbol->getResolvedMethod()->isJNINative() && calltarget->_calleeSymbol->getResolvedMethod()->isStatic() && calltarget->_myCallSite->_callNode->isPreparedForDirectJNI())4745argNodeIndex++;47464747for ( ; parm ; parm = parm->getNext(), ++argNodeIndex )4748{4749TR::Node *arg = calltarget->_myCallSite->_callNode->getChild(argNodeIndex);47504751parm->_parameterNode = arg;47524753if (arg->getDataType() != parm->_parmSymbol->getDataType() &&4754(parm->_parmSymbol->getDataType() != TR::Aggregate))4755{4756heuristicTrace(tracer(), "For argNodeIndex %d, data type of node %p does not match data type of parameter. Removing Call Target for Safety's sake.", argNodeIndex, arg);4757calltarget->_myCallSite->removecalltarget(calltarget, tracer(), Cant_Match_Parms_to_Args);47584759if (!comp()->fej9()->canAllowDifferingNumberOrTypesOfArgsAndParmsInInliner())4760TR_ASSERT(0, "Can't match args to parms. Data type mismatch.");47614762return false;4763}4764}4765return true;4766}47674768bool4769TR_J9InlinerPolicy::supressInliningRecognizedInitialCallee(TR_CallSite* callsite, TR::Compilation* comp)4770{4771TR_ResolvedMethod * initialCalleeMethod = callsite->_initialCalleeMethod;47724773if (initialCalleeMethod)4774{4775switch (initialCalleeMethod->getRecognizedMethod())4776{4777/*4778* Inline this group of methods when the compiling method is shared method handle thunk.4779* Otherwise, they can be folded away by VP and should not be inlined here.4780*/4781case TR::java_lang_invoke_DirectHandle_nullCheckIfRequired:4782case TR::java_lang_invoke_PrimitiveHandle_initializeClassIfRequired:4783case TR::java_lang_invoke_MethodHandle_invokeExactTargetAddress:4784{4785TR::IlGeneratorMethodDetails & details = comp->ilGenRequest().details();4786if (details.isMethodHandleThunk())4787{4788J9::MethodHandleThunkDetails & thunkDetails = static_cast<J9::MethodHandleThunkDetails &>(details);4789return thunkDetails.isCustom();4790}4791return true;4792}47934794default:4795break;4796}4797}4798return (callsite->_callNode && comp->fej9()->supressInliningRecognizedInitialCallee(callsite, comp));4799}48004801static bool4802isDecimalFormatPattern(TR::Compilation *comp, TR_ResolvedMethod *method)4803{4804// look for the NumberFormat pattern4805//4806// [ 0], 0, JBaload0getfield4807// [ 1], 1, JBgetfield Ljava/text/NumberFormat;4808// [ 4], 4, JBaload1 Ljava/math/BigDecimal;4809// [ 5], 5, JBinvokevirtual BigDecimal.doubleValue()D or BigDecimal.floatValue()F4810// [ 8], 8, JBf2d if floatValue4811// [ 8], 8, JBinvokevirtual NumberFormat.format(D)Ljava/lang/String;4812// [ b], 11, JBreturn14813//4814// don't inline such methods as we want to run stringpeepholes when compiled on their own4815// so that the decimalFormat optimization can be applied4816//48174818TR_J9ByteCodeIterator bci(0, static_cast<TR_ResolvedJ9Method *> (method), comp->fej9(), comp);48194820// maxbytecode could be 12 or 13 depending on whether4821// doubleValue or floatValue is called4822//4823if (bci.maxByteCodeIndex() > 13)4824return false;4825int32_t bcCount = 0;4826TR::DataType type = TR::NoType;4827uint32_t fieldOffset;4828bool isUnresolvedInCP;4829TR_J9ByteCode bc = bci.first();4830if (bc == J9BCunknown) return false;4831if (bc != J9BCaload0) return false;4832bc = bci.next(); // matched 1st bc48334834if (bc == J9BCgetfield)4835{4836bool isVolatile, isPrivate, resolved;4837resolved = method->fieldAttributes(comp, bci.next2Bytes(), &fieldOffset, &type, &isVolatile, 0, &isPrivate, false, &isUnresolvedInCP);4838if (!resolved || isUnresolvedInCP)4839return false;4840else if (type != TR::Address)4841return false;48424843// TODO: make sure the field is recognized as a NumberFormat4844//4845bc = bci.next(); //matched 2nd bc4846}4847else4848return false;48494850if (bc != J9BCaload1)4851return false;4852bc = bci.next(); // matched 3rd bc48534854bool isFloat = false;4855if (bc == J9BCinvokevirtual)4856{4857int32_t cpIndex = bci.next2Bytes();4858TR_ResolvedMethod *resolvedMethod = method->getResolvedVirtualMethod(comp, cpIndex, true, &isUnresolvedInCP);4859if (resolvedMethod &&4860(resolvedMethod->getRecognizedMethod() == TR::java_math_BigDecimal_doubleValue ||4861resolvedMethod->getRecognizedMethod() == TR::java_math_BigDecimal_floatValue))4862{4863if (resolvedMethod->getRecognizedMethod() == TR::java_math_BigDecimal_floatValue)4864isFloat = true;4865bc = bci.next(); // matched 4th bc4866}4867else4868return false;4869}4870else4871return false;48724873if (isFloat)4874{4875if (bc != J9BCf2d)4876return false;4877bc = bci.next(); // matched 5th bc if floatValue4878}48794880if (bc == J9BCinvokevirtual)4881{4882int32_t cpIndex = bci.next2Bytes();4883TR_ResolvedMethod *resolvedMethod = method->getResolvedVirtualMethod(comp, cpIndex, true, &isUnresolvedInCP);4884if (resolvedMethod &&4885resolvedMethod->getRecognizedMethod() == TR::java_text_NumberFormat_format)4886{4887bc = bci.next(); // matched 5th (or 6th) bc4888}4889else4890return false;4891}4892else4893return false;48944895if (bc != J9BCgenericReturn)4896return false; // matched 6th (or 7th) bc48974898///traceMsg(comp, "pattern matched successfully\n");4899return true;4900}49014902TR_InlinerFailureReason4903TR_J9JSR292InlinerPolicy::checkIfTargetInlineable(TR_CallTarget* target, TR_CallSite* callsite, TR::Compilation* comp)4904{4905// for GPU, skip all the heuristic for JSR292 related methods4906if (comp->hasIntStreamForEach())4907return DontInline_Callee;49084909TR_ResolvedMethod * resolvedMethod = target->_calleeSymbol ? target->_calleeSymbol->getResolvedMethod():target->_calleeMethod;4910if (!isJSR292Method(resolvedMethod))4911return DontInline_Callee;49124913if (isJSR292AlwaysWorthInlining(resolvedMethod))4914return InlineableTarget;4915else if (comp->getCurrentMethod()->convertToMethod()->isArchetypeSpecimen() ||4916comp->getCurrentMethod()->getRecognizedMethod() == TR::java_lang_invoke_MethodHandle_invokeExact)4917{4918//we are ourselves an archetype specimen, so we can inline other archetype speciman4919return InlineableTarget;4920}4921else if (comp->getMethodHotness() >= warm)4922{4923// We are not an archetype specimen4924// but because we're warm (or greater) we are allowed to inline JSR292 methods4925return InlineableTarget;4926}49274928//we are not an archetype specimen ourselves and we are cold or below, No inlining of JSR292 methods.4929return DontInline_Callee;4930}49314932TR_InlinerFailureReason4933TR_J9InlinerPolicy::checkIfTargetInlineable(TR_CallTarget* target, TR_CallSite* callsite, TR::Compilation* comp)4934{4935if (comp->compileRelocatableCode() && comp->getMethodHotness() <= cold)4936{4937// If we are an AOT cold compile, don't inline4938return DontInline_Callee;4939}49404941TR_ResolvedMethod * resolvedMethod = target->_calleeSymbol ? target->_calleeSymbol->getResolvedMethod():target->_calleeMethod;49424943if (!isInlineableJNI(resolvedMethod,callsite->_callNode) || callsite->isIndirectCall())4944{4945if (!target->_calleeMethod->isCompilable(comp->trMemory()) || !target->_calleeMethod->isInlineable(comp))4946{4947return Not_Compilable_Callee;4948}49494950if (target->_calleeMethod->isJNINative())4951{4952return JNI_Callee;4953}4954}49554956TR::RecognizedMethod rm = resolvedMethod->getRecognizedMethod();49574958// Don't inline methods that are going to be reduced in ilgen or UnsafeFastPath4959switch (rm)4960{4961case TR::com_ibm_jit_JITHelpers_getByteFromArray:4962case TR::com_ibm_jit_JITHelpers_getByteFromArrayByIndex:4963case TR::com_ibm_jit_JITHelpers_getByteFromArrayVolatile:4964case TR::com_ibm_jit_JITHelpers_getCharFromArray:4965case TR::com_ibm_jit_JITHelpers_getCharFromArrayByIndex:4966case TR::com_ibm_jit_JITHelpers_getCharFromArrayVolatile:4967case TR::com_ibm_jit_JITHelpers_getIntFromArray:4968case TR::com_ibm_jit_JITHelpers_getIntFromArrayVolatile:4969case TR::com_ibm_jit_JITHelpers_getIntFromObject:4970case TR::com_ibm_jit_JITHelpers_getIntFromObjectVolatile:4971case TR::com_ibm_jit_JITHelpers_getLongFromArray:4972case TR::com_ibm_jit_JITHelpers_getLongFromArrayVolatile:4973case TR::com_ibm_jit_JITHelpers_getLongFromObject:4974case TR::com_ibm_jit_JITHelpers_getLongFromObjectVolatile:4975case TR::com_ibm_jit_JITHelpers_getObjectFromArray:4976case TR::com_ibm_jit_JITHelpers_getObjectFromArrayVolatile:4977case TR::com_ibm_jit_JITHelpers_getObjectFromObject:4978case TR::com_ibm_jit_JITHelpers_getObjectFromObjectVolatile:4979case TR::com_ibm_jit_JITHelpers_putByteInArray:4980case TR::com_ibm_jit_JITHelpers_putByteInArrayByIndex:4981case TR::com_ibm_jit_JITHelpers_putByteInArrayVolatile:4982case TR::com_ibm_jit_JITHelpers_putCharInArray:4983case TR::com_ibm_jit_JITHelpers_putCharInArrayByIndex:4984case TR::com_ibm_jit_JITHelpers_putCharInArrayVolatile:4985case TR::com_ibm_jit_JITHelpers_putIntInArray:4986case TR::com_ibm_jit_JITHelpers_putIntInArrayVolatile:4987case TR::com_ibm_jit_JITHelpers_putIntInObject:4988case TR::com_ibm_jit_JITHelpers_putIntInObjectVolatile:4989case TR::com_ibm_jit_JITHelpers_putLongInArray:4990case TR::com_ibm_jit_JITHelpers_putLongInArrayVolatile:4991case TR::com_ibm_jit_JITHelpers_putLongInObject:4992case TR::com_ibm_jit_JITHelpers_putLongInObjectVolatile:4993case TR::com_ibm_jit_JITHelpers_putObjectInArray:4994case TR::com_ibm_jit_JITHelpers_putObjectInArrayVolatile:4995case TR::com_ibm_jit_JITHelpers_putObjectInObject:4996case TR::com_ibm_jit_JITHelpers_putObjectInObjectVolatile:4997case TR::com_ibm_jit_JITHelpers_byteToCharUnsigned:4998case TR::com_ibm_jit_JITHelpers_acmplt:4999case TR::com_ibm_jit_JITHelpers_isArray:5000case TR::com_ibm_jit_JITHelpers_getJ9ClassFromObject32:5001case TR::com_ibm_jit_JITHelpers_getJ9ClassFromObject64:5002case TR::com_ibm_jit_JITHelpers_getClassInitializeStatus:5003case TR::java_lang_StringUTF16_getChar:5004case TR::java_lang_StringUTF16_putChar:5005case TR::java_lang_StringUTF16_toBytes:5006case TR::java_lang_invoke_MethodHandle_asType:5007return DontInline_Callee;5008default:5009break;5010}50115012/**5013* Do not inline LambdaForm generated reinvoke() methods as they are on the5014* slow path and may consume inlining budget.5015*/5016if (comp->fej9()->isLambdaFormGeneratedMethod(resolvedMethod))5017{5018if (resolvedMethod->nameLength() == strlen("reinvoke") &&5019!strncmp(resolvedMethod->nameChars(), "reinvoke", strlen("reinvoke")))5020{5021traceMsg(comp, "Intentionally avoided inlining generated %.*s.%.*s%.*s\n",5022resolvedMethod->classNameLength(), resolvedMethod->classNameChars(),5023resolvedMethod->nameLength(), resolvedMethod->nameChars(),5024resolvedMethod->signatureLength(), resolvedMethod->signatureChars());5025return DontInline_Callee;5026}5027}50285029if (comp->getOptions()->getEnableGPU(TR_EnableGPU))5030{5031switch (rm)5032{5033case TR::java_util_stream_AbstractPipeline_evaluate:5034traceMsg(comp, "Intentionally avoided inlining evaluate\n");5035return Recognized_Callee;5036break;5037default:5038break;5039}5040}50415042if (comp->getOptions()->getEnableGPU(TR_EnableGPUEnableMath))5043{5044switch (rm)5045{5046case TR::java_lang_Math_abs_F:5047case TR::java_lang_Math_abs_D:5048case TR::java_lang_Math_exp:5049case TR::java_lang_Math_log:5050case TR::java_lang_Math_sqrt:5051case TR::java_lang_Math_sin:5052case TR::java_lang_Math_cos:5053traceMsg(comp, "Intentionally avoided inlining MathMethod\n");5054return Recognized_Callee;5055default:5056break;5057}5058}50595060#ifdef J9VM_OPT_JAVA_CRYPTO_ACCELERATION5061if (comp->fej9()->inlineRecognizedCryptoMethod(target, comp))5062{5063return Recognized_Callee;5064}5065#endif50665067if (5068rm == TR::com_ibm_jit_JITHelpers_toUpperIntrinsicLatin1 ||5069rm == TR::com_ibm_jit_JITHelpers_toLowerIntrinsicUTF16 ||5070rm == TR::com_ibm_jit_JITHelpers_toUpperIntrinsicLatin1 ||5071rm == TR::com_ibm_jit_JITHelpers_toLowerIntrinsicUTF16 ||50725073rm == TR::java_lang_String_compressedArrayCopy_BIBII ||5074rm == TR::java_lang_String_compressedArrayCopy_BICII ||5075rm == TR::java_lang_String_compressedArrayCopy_CIBII ||5076rm == TR::java_lang_String_compressedArrayCopy_CICII ||5077rm == TR::java_lang_String_decompressedArrayCopy_BIBII ||5078rm == TR::java_lang_String_decompressedArrayCopy_BICII ||5079rm == TR::java_lang_String_decompressedArrayCopy_CIBII ||5080rm == TR::java_lang_String_decompressedArrayCopy_CICII ||5081rm == TR::java_lang_Math_max_D ||5082rm == TR::java_lang_Math_min_D ||5083//DAA Intrinsic methods will get reduced if intrinsics are on, so don't consider it as a target5084(resolvedMethod->isDAAMarshallingIntrinsicMethod() && !comp->getOption(TR_DisableMarshallingIntrinsics)) ||5085(resolvedMethod->isDAAPackedDecimalIntrinsicMethod() && !comp->getOption(TR_DisablePackedDecimalIntrinsics)) ||50865087// dont inline methods that contain the NumberFormat pattern5088// this is because we want to catch the opportunity with stringpeepholes5089// and stringpeepholes runs before inliner. so if the calleemethod contained5090// the pattern and it got inlined, we would never find the pattern5091isDecimalFormatPattern(comp, target->_calleeMethod))5092{5093return Recognized_Callee;5094}50955096return InlineableTarget;5097}50985099bool TR_J9InlinerPolicy::isJSR292Method(TR_ResolvedMethod *resolvedMethod)5100{5101if (isJSR292AlwaysWorthInlining(resolvedMethod))5102return true;51035104TR::RecognizedMethod method = resolvedMethod->getRecognizedMethod();5105if (method == TR::java_lang_invoke_MethodHandle_invokeExact)5106return true;5107return false;5108}51095110bool TR_J9InlinerPolicy::isJSR292AlwaysWorthInlining(TR_ResolvedMethod *resolvedMethod)5111{5112TR::RecognizedMethod method = resolvedMethod->getRecognizedMethod();5113if (method == TR::java_lang_invoke_MethodHandle_invokeExact)5114return true;51155116if (TR_J9MethodBase::isVarHandleOperationMethod(method))5117return true;51185119if (isJSR292SmallGetterMethod(resolvedMethod))5120return true;51215122if (isJSR292SmallHelperMethod(resolvedMethod))5123return true;51245125if (resolvedMethod->convertToMethod()->isArchetypeSpecimen())5126return true;51275128if (TR::comp()->fej9()->isLambdaFormGeneratedMethod(resolvedMethod))5129return true;51305131return false;5132}51335134bool TR_J9InlinerPolicy::isJSR292SmallHelperMethod(TR_ResolvedMethod *resolvedMethod)5135{5136TR::RecognizedMethod method = resolvedMethod->getRecognizedMethod();5137switch (method)5138{5139case TR::java_lang_invoke_ConvertHandleFilterHelpers_object2J:5140case TR::java_lang_invoke_ConvertHandleFilterHelpers_number2J:5141case TR::java_lang_invoke_MethodHandle_doCustomizationLogic:5142case TR::java_lang_invoke_MethodHandle_undoCustomizationLogic:5143return true;51445145default:5146break;5147}5148return false;5149}51505151bool TR_J9InlinerPolicy::isJSR292SmallGetterMethod(TR_ResolvedMethod *resolvedMethod)5152{5153TR::RecognizedMethod method = resolvedMethod->getRecognizedMethod();5154// small getters5155switch (method)5156{5157case TR::java_lang_invoke_MutableCallSite_getTarget:5158case TR::java_lang_invoke_MethodHandle_type:5159case TR::java_lang_invoke_DirectMethodHandle_internalMemberName:5160case TR::java_lang_invoke_MethodHandleImpl_CountingWrapper_getTarget:5161return true;51625163default:5164break;5165}5166return false;5167}51685169void5170TR_J9InlinerUtil::estimateAndRefineBytecodeSize(TR_CallSite* callsite, TR_CallTarget* calltarget, TR_CallStack *callStack, int32_t &bytecodeSize)5171{5172if (comp()->getOptLevel() >= warm && bytecodeSize > 100)5173{5174//We call to calculateCodeSize to simply get an estimate.5175//We don't want the original calltarget to be modified and become inconsistent in any way5176//Please see 196749 for more details51775178calltarget->_originatingBlock = (callsite->_callerBlock != NULL) ? callsite->_callerBlock : (callsite->_callNodeTreeTop ? callsite->_callNodeTreeTop->getEnclosingBlock() : 0);5179bool estimateIsFine = false;5180if (calltarget->_originatingBlock && calltarget->_calleeSymbol)5181{5182TR_CallTarget callTargetClone (*calltarget);5183TR_EstimateCodeSize::raiiWrapper ecsWrapper(inliner(), tracer(), inliner()->getMaxRecursiveCallByteCodeSizeEstimate());5184TR_EstimateCodeSize *ecs = ecsWrapper.getCodeEstimator();5185vcount_t origVisitCount = comp()->getVisitCount();5186estimateIsFine = ecs->calculateCodeSize(&callTargetClone, callStack, false);5187comp()->setVisitCount(origVisitCount);51885189if (estimateIsFine)5190{5191if (comp()->trace(OMR::inlining))5192traceMsg( comp(), "Partial estimate for this target %d, full size %d, real bytecode size %d\n", callTargetClone._partialSize, callTargetClone._fullSize, bytecodeSize);51935194bytecodeSize = callTargetClone._fullSize;5195if (comp()->trace(OMR::inlining))5196traceMsg( comp(), "Reducing bytecode size to %d\n", bytecodeSize);5197}5198}5199}5200}52015202TR_PrexArgInfo* TR_PrexArgInfo::argInfoFromCaller(TR::Node* callNode, TR_PrexArgInfo* callerArgInfo)5203{5204TR::Compilation* compilation = TR::comp();5205bool tracePrex = compilation->trace(OMR::inlining) || compilation->trace(OMR::invariantArgumentPreexistence);52065207int32_t firstArgIndex = callNode->getFirstArgumentIndex();5208int32_t numArgs = callNode->getNumArguments();5209int32_t numChildren = callNode->getNumChildren();52105211TR_PrexArgInfo* argInfo = new (compilation->trHeapMemory()) TR_PrexArgInfo(numArgs, compilation->trMemory());52125213for (int32_t i = firstArgIndex; i < numChildren; i++)5214{5215TR::Node* child = callNode->getChild(i);5216if (TR_PrexArgInfo::hasArgInfoForChild(child, callerArgInfo))5217{5218argInfo->set(i - firstArgIndex, TR_PrexArgInfo::getArgForChild(child, callerArgInfo));5219if (tracePrex)5220traceMsg(compilation, "Arg %d is from caller\n", i - firstArgIndex);5221}5222}5223return argInfo;5224}52255226TR_PrexArgInfo *5227TR_J9InlinerUtil::computePrexInfo(TR_CallTarget *target, TR_PrexArgInfo *callerArgInfo)5228{5229if (comp()->getOption(TR_DisableInlinerArgsPropagation))5230return NULL;52315232TR_CallSite *site = target->_myCallSite;5233if (!site || !site->_callNode)5234return NULL;52355236bool tracePrex = comp()->trace(OMR::inlining) || comp()->trace(OMR::invariantArgumentPreexistence);52375238auto prexArgInfoFromTarget = createPrexArgInfoForCallTarget(target->_guard, target->_calleeMethod);5239auto prexArgInfoFromCallSite = TR_J9InlinerUtil::computePrexInfo(inliner(), site, callerArgInfo);5240auto prexArgInfo = TR_PrexArgInfo::enhance(prexArgInfoFromTarget, prexArgInfoFromCallSite, comp());52415242if (tracePrex && prexArgInfo)5243{5244traceMsg(comp(), "PREX.inl: argInfo for target %p\n", target);5245prexArgInfo->dumpTrace();5246}52475248// At this stage, we can improve the type of the virtual guard we are going to use5249// For a non-overridden guard or for an interface guard, if it makes sense, try to use a vft-test5250// based virtual guard5251//5252bool disablePreexForChangedGuard = false;5253TR_PersistentCHTable * chTable = comp()->getPersistentInfo()->getPersistentCHTable();5254TR_PersistentClassInfo *thisClassInfo = chTable->findClassInfoAfterLocking(target->_receiverClass, comp());5255if (target->_calleeSymbol->hasThisCalls() &&5256target->_receiverClass &&5257!TR::Compiler->cls.isAbstractClass(comp(), target->_receiverClass) &&5258!fe()->classHasBeenExtended(target->_receiverClass) &&5259thisClassInfo &&5260thisClassInfo->isInitialized() &&5261((target->_guard->_kind == TR_NonoverriddenGuard && target->_guard->_type == TR_NonoverriddenTest) ||5262(target->_guard->_kind == TR_InterfaceGuard)) &&5263performTransformation(comp(), "O^O VIRTUAL GUARD IMPROVE: Changed guard kind %s type %s to use VFT test\n", tracer()->getGuardKindString(target->_guard), tracer()->getGuardTypeString(target->_guard)))5264{5265target->_guard->_type = TR_VftTest;5266target->_guard->_thisClass = target->_receiverClass;5267}52685269return prexArgInfo;5270}52715272TR_PrexArgInfo *5273TR_J9InlinerUtil::computePrexInfo(TR_CallTarget *target)5274{5275return computePrexInfo(target, NULL);5276}52775278/** \brief5279* Find the def to an auto or parm before treetop in a extended basic block5280*5281* \return5282* The treetop containing the def (the store)5283*/5284static TR::TreeTop*5285defToAutoOrParmInEBB(TR::Compilation* comp, TR::TreeTop* treetop, TR::SymbolReference* symRef, TR::Node** valueNode)5286{5287for (;treetop != NULL; treetop= treetop->getPrevTreeTop())5288{5289auto ttNode = treetop->getNode();5290if (ttNode->getOpCodeValue() == TR::BBStart)5291{5292auto block = ttNode->getBlock();5293if (!block->isExtensionOfPreviousBlock())5294return NULL;5295else5296continue;5297}52985299auto storeNode = ttNode->getStoreNode();5300if (storeNode &&5301storeNode->getOpCode().isStoreDirect() &&5302storeNode->getSymbolReference() == symRef)5303{5304auto child = storeNode->getFirstChild();5305// If the child is also an auto, keep walking the trees to find the child's def5306if (child->getOpCode().hasSymbolReference() &&5307child->getSymbolReference()->getSymbol()->isAuto() &&5308!child->getSymbolReference()->hasKnownObjectIndex())5309{5310symRef = child->getSymbolReference();5311continue;5312}53135314if (valueNode)5315*valueNode = child;53165317return treetop;5318}5319}53205321return NULL;5322}53235324/** \brief5325* Find the first occurrence of the load in a extended basic block5326*5327* \return5328* The treetop containing the first occurrence of the load5329*/5330static TR::TreeTop*5331getFirstOccurrenceOfLoad(TR::Compilation* comp, TR::TreeTop* treetop, TR::Node* loadNode)5332{5333// Get the first treetop of this EBB.5334auto treetopEntry = treetop->getEnclosingBlock()->startOfExtendedBlock()->getEntry();5335auto visitCount = comp->incOrResetVisitCount();53365337for (treetop = treetopEntry; treetop != NULL; treetop = treetop->getNextTreeTop())5338{5339auto ttNode = treetop->getNode();5340if (ttNode->containsNode(loadNode, visitCount))5341{5342return treetop;5343}5344}5345return NULL;5346}53475348TR_PrexArgInfo *5349TR_J9InlinerUtil::computePrexInfo(TR_InlinerBase *inliner, TR_CallSite* site, TR_PrexArgInfo *callerArgInfo)5350{5351TR::Compilation* comp = inliner->comp();53525353if (comp->getOption(TR_DisableInlinerArgsPropagation))5354return NULL;53555356if (!site->_callNode)5357return NULL;53585359auto callNode = site->_callNode;53605361// We want to avoid degrading info we already have from another source like VP.5362// Unfortunately that desire mucks up this function with a lot of logic that5363// looks like constraint merging, and is redundant with what VP already does.5364//5365TR_PrexArgInfo *prexArgInfo = NULL;5366// Interface call doesn't have a resolved _intialCalleeMethod, so callee can be NULL5367auto callee = site->_initialCalleeMethod;53685369bool tracePrex = comp->trace(OMR::inlining) || comp->trace(OMR::invariantArgumentPreexistence);5370if (tracePrex)5371traceMsg(comp, "PREX.inl: Populating prex argInfo for [%p] %s %s\n", callNode, callNode->getOpCode().getName(), callNode->getSymbol()->castToMethodSymbol()->getMethod()->signature(inliner->trMemory(), stackAlloc));53725373int32_t firstArgIndex = callNode->getFirstArgumentIndex();5374for (int32_t c = callNode->getNumChildren() -1; c >= firstArgIndex; c--)5375{5376int32_t argOrdinal = c - firstArgIndex;53775378TR::Node *argument = callNode->getChild(c);5379if (tracePrex)5380{5381traceMsg(comp, "PREX.inl: Child %d [%p] n%dn %s %s\n",5382c, argument,5383argument->getGlobalIndex(),5384argument->getOpCode().getName(),5385argument->getOpCode().hasSymbolReference()? argument->getSymbolReference()->getName(comp->getDebug()) : "");5386}53875388if (!argument->getOpCode().hasSymbolReference() || argument->getDataType() != TR::Address)5389continue;53905391auto symRef = argument->getSymbolReference();5392auto symbol = symRef->getSymbol();53935394TR_PrexArgument* prexArg = NULL;53955396if (c == callNode->getFirstArgumentIndex() &&5397callee &&5398callee->convertToMethod()->isArchetypeSpecimen() &&5399callee->getMethodHandleLocation() &&5400comp->getOrCreateKnownObjectTable())5401{5402// Here's a situation where inliner is taking it upon itself to draw5403// conclusions about known objects. VP won't get a chance to figure this5404// out before we go ahead and do the inlining, so we'd better populate5405// the prex info now.5406//5407// (If VP did this stuff instead of inliner, it might work a bit more naturally.)5408//5409TR::KnownObjectTable::Index methodHandleIndex = comp->getKnownObjectTable()->getOrCreateIndexAt(callee->getMethodHandleLocation());5410prexArg = new (inliner->trHeapMemory()) TR_PrexArgument(methodHandleIndex, comp);5411if (tracePrex)5412{5413TR::Node *mh = callNode->getArgument(0);5414traceMsg(comp, "PREX.inl: %p: %p is known object obj%d in inlined call [%p]\n", prexArg, mh, methodHandleIndex, callNode);5415}5416}5417else if (symRef->hasKnownObjectIndex())5418{5419prexArg = new (inliner->trHeapMemory()) TR_PrexArgument(symRef->getKnownObjectIndex(), comp);5420if (tracePrex)5421traceMsg(comp, "PREX.inl: %p: is symref known object obj%d\n", prexArg, symRef->getKnownObjectIndex());5422}5423else if (argument->hasKnownObjectIndex())5424{5425prexArg = new (inliner->trHeapMemory()) TR_PrexArgument(argument->getKnownObjectIndex(), comp);5426if (tracePrex)5427traceMsg(comp, "PREX.inl: %p: is node known object obj%d\n", prexArg, argument->getKnownObjectIndex());5428}5429else if (argument->getOpCodeValue() == TR::aload)5430{5431OMR::ParameterSymbol *parmSymbol = symbol->getParmSymbol();5432if (parmSymbol && !prexArg)5433{5434if (parmSymbol->getFixedType())5435{5436prexArg = new (inliner->trHeapMemory()) TR_PrexArgument(TR_PrexArgument::ClassIsFixed, (TR_OpaqueClassBlock *) parmSymbol->getFixedType());5437if (tracePrex)5438{5439char *sig = TR::Compiler->cls.classSignature(comp, (TR_OpaqueClassBlock*)parmSymbol->getFixedType(), inliner->trMemory());5440traceMsg(comp, "PREX.inl: %p: is load of parm with fixed class %p %s\n", prexArg, parmSymbol->getFixedType(), sig);5441}5442}5443if (parmSymbol->getIsPreexistent())5444{5445int32_t len = 0;5446const char *sig = parmSymbol->getTypeSignature(len);5447TR_OpaqueClassBlock *clazz = comp->fe()->getClassFromSignature(sig, len, site->_callerResolvedMethod);54485449if (clazz)5450{5451prexArg = new (inliner->trHeapMemory()) TR_PrexArgument(TR_PrexArgument::ClassIsPreexistent, clazz);5452if (tracePrex)5453traceMsg(comp, "PREX.inl: %p: is preexistent\n", prexArg);5454}5455}5456}5457else if (symbol->isAuto())5458{5459TR::Node* valueNode = NULL;5460TR::TreeTop* ttForFirstOccurrence = getFirstOccurrenceOfLoad(comp, site->_callNodeTreeTop, argument);5461TR_ASSERT_FATAL(ttForFirstOccurrence, "Could not get a treetop for the first occurence of %p", argument);5462defToAutoOrParmInEBB(comp, ttForFirstOccurrence, symRef, &valueNode);5463if (valueNode &&5464valueNode->getOpCode().hasSymbolReference() &&5465valueNode->getSymbolReference()->hasKnownObjectIndex())5466{5467prexArg = new (inliner->trHeapMemory()) TR_PrexArgument(valueNode->getSymbolReference()->getKnownObjectIndex(), comp);5468if (tracePrex)5469traceMsg(comp, "PREX.inl: %p: is known object obj%d, argument n%dn has def from n%dn %s %s\n",5470prexArg,5471prexArg->getKnownObjectIndex(),5472argument->getGlobalIndex(),5473valueNode->getGlobalIndex(),5474valueNode->getOpCode().getName(),5475valueNode->getSymbolReference()->getName(comp->getDebug()));5476}5477}5478}5479else if (symRef == comp->getSymRefTab()->findJavaLangClassFromClassSymbolRef())5480{5481TR::Node *argFirstChild = argument->getFirstChild();5482if (argFirstChild->getOpCodeValue() == TR::loadaddr &&5483argFirstChild->getSymbol()->isStatic() &&5484!argFirstChild->getSymbolReference()->isUnresolved() &&5485argFirstChild->getSymbol()->isClassObject() &&5486argFirstChild->getSymbol()->castToStaticSymbol()->getStaticAddress())5487{5488uintptr_t objectReferenceLocation = (uintptr_t)argFirstChild->getSymbolReference()->getSymbol()->castToStaticSymbol()->getStaticAddress();5489TR::KnownObjectTable *knot = comp->getOrCreateKnownObjectTable();5490if (knot)5491{5492TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());5493auto knownObjectIndex = knot->getOrCreateIndexAt((uintptr_t*)(objectReferenceLocation + fej9->getOffsetOfJavaLangClassFromClassField()));5494prexArg = new (comp->trHeapMemory()) TR_PrexArgument(knownObjectIndex, comp);5495if (tracePrex)5496traceMsg(comp, "PREX.inl is known java/lang/Class obj%d\n", prexArg, knownObjectIndex);5497}5498}5499}55005501if (prexArg)5502{5503if (!prexArgInfo)5504prexArgInfo = new (inliner->trHeapMemory()) TR_PrexArgInfo(callNode->getNumArguments(), inliner->trMemory());5505prexArgInfo->set(argOrdinal, prexArg);5506}5507}55085509if (tracePrex)5510traceMsg(comp, "PREX.inl: Done populating prex argInfo for %s %p\n", callNode->getOpCode().getName(), callNode);55115512if (tracePrex && prexArgInfo)5513{5514traceMsg(comp, "PREX.inl: argInfo for callsite %p\n", site);5515prexArgInfo->dumpTrace();5516}55175518if (callerArgInfo)5519{5520if (tracePrex)5521traceMsg(comp, "PREX.inl: Propagating prex argInfo from caller for [%p] %s %s\n",5522callNode,5523callNode->getOpCode().getName(),5524callNode->getSymbol()->castToMethodSymbol()->getMethod()->signature(inliner->trMemory(), stackAlloc));55255526TR_PrexArgInfo* argsFromCaller = TR_PrexArgInfo::argInfoFromCaller(callNode, callerArgInfo);5527prexArgInfo = TR_PrexArgInfo::enhance(prexArgInfo, argsFromCaller, comp);55285529if (tracePrex)5530{5531traceMsg(comp, "PREX.inl: argInfo for callsite %p after propagating argInfo from caller\n", site);5532prexArgInfo->dumpTrace();5533}5534}55355536return prexArgInfo;5537}55385539bool TR_J9InlinerUtil::needTargetedInlining(TR::ResolvedMethodSymbol *callee)5540{5541// Trees from archetype specimens may not match the archetype method's bytecodes,5542// so there may be some calls things that inliner missed.5543//5544// Tactically, we also inline again based on hasMethodHandleInvokes because EstimateCodeSize5545// doesn't yet cope with invokeHandle, invokeHandleGeneric, and invokeDynamic (but it should).5546//5547if (callee->getMethod()->isArchetypeSpecimen() ||5548callee->hasMethodHandleInvokes())5549return true;5550return false;5551}55525553/** Find arguments which refer to constant classes5554If a parameter refers to a constant class, set the known object index in _ecsPrexArgInfo5555of the target.5556*/5557void TR_J9InlinerUtil::checkForConstClass(TR_CallTarget *target, TR_LogTracer *tracer)5558{5559static char *disableCCI=feGetEnv("TR_DisableConstClassInlining");55605561if (disableCCI || !tracer || !target) return;55625563TR_CallSite *site = target->_myCallSite;5564if (!site) return;55655566TR::Node* callNode = site->_callNode;5567if (!callNode) return;55685569TR_PrexArgInfo *ecsArgInfo = target->_ecsPrexArgInfo;5570if (!ecsArgInfo) return;55715572TR::Compilation * comp = tracer->comp();5573bool tracePrex = comp->trace(OMR::inlining) || comp->trace(OMR::invariantArgumentPreexistence);55745575if (tracePrex)5576traceMsg(comp, "checkForConstClass parm for [%p] %s %s\n", callNode, callNode->getOpCode().getName(), callNode->getSymbol()->castToMethodSymbol()->getMethod()->signature(comp->trMemory(), stackAlloc));55775578// loop over args5579int32_t firstArgIndex = callNode->getFirstArgumentIndex();5580for (int32_t c = callNode->getNumChildren()-1; c >= firstArgIndex; c--)5581{5582int32_t argOrdinal = c - firstArgIndex;55835584// Check that argOrdinal is a valid index for ecsArgInfo.5585if (argOrdinal >= ecsArgInfo->getNumArgs())5586{5587traceMsg(comp, "checkForConstClass skipping c=%d because argOrdinal(%d) >= numArgs(%d)\n", c, argOrdinal, ecsArgInfo->getNumArgs());5588continue;5589}55905591TR_PrexArgument *prexArgument = ecsArgInfo->get(argOrdinal);55925593PrexKnowledgeLevel priorKnowledge = TR_PrexArgument::knowledgeLevel(prexArgument);55945595TR::Node *argument = callNode->getChild(c);5596if (tracePrex)5597{5598traceMsg(comp, "checkForConstClass: Child %d [%p] arg %p %s%s %s\n",5599c, argument, prexArgument, TR_PrexArgument::priorKnowledgeStrings[priorKnowledge],5600argument->getOpCode().getName(),5601argument->getOpCode().hasSymbolReference()? argument->getSymbolReference()->getName(comp->getDebug()) : "");5602}56035604TR::KnownObjectTable::Index knownObjectIndex;5605bool knownObjectClass = false;56065607if (argument->getOpCode().hasSymbolReference() &&5608(argument->getSymbolReference() == comp->getSymRefTab()->findJavaLangClassFromClassSymbolRef()))5609{5610TR::Node *argFirstChild = argument->getFirstChild();5611if (argFirstChild->getOpCode().hasSymbolReference() &&5612argFirstChild->getSymbol()->isStatic() &&5613!argFirstChild->getSymbolReference()->isUnresolved() &&5614argFirstChild->getSymbol()->isClassObject())5615{5616uintptr_t objectReferenceLocation = (uintptr_t)argFirstChild->getSymbolReference()->getSymbol()->castToStaticSymbol()->getStaticAddress();5617if (objectReferenceLocation)5618{5619TR::KnownObjectTable *knot = comp->getOrCreateKnownObjectTable();5620if (knot)5621{5622TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());5623knownObjectIndex = knot->getOrCreateIndexAt((uintptr_t*)(objectReferenceLocation + fej9->getOffsetOfJavaLangClassFromClassField()));5624knownObjectClass = true;5625}5626}5627}5628}56295630if (argument->getOpCode().hasSymbolReference() && (knownObjectClass || argument->getSymbolReference()->hasKnownObjectIndex()))5631{5632if (priorKnowledge < KNOWN_OBJECT)5633{5634if (knownObjectClass)5635{5636ecsArgInfo->set(argOrdinal, new (comp->trStackMemory()) TR_PrexArgument(knownObjectIndex, comp));5637if (tracePrex)5638traceMsg(comp, "checkForConstClass: %p: is known object obj%d (knownObjectClass)\n", ecsArgInfo->get(argOrdinal), knownObjectIndex);5639}5640else5641{5642ecsArgInfo->set(argOrdinal, new (comp->trStackMemory()) TR_PrexArgument(argument->getSymbolReference()->getKnownObjectIndex(), comp));5643if (tracePrex)5644traceMsg(comp, "checkForConstClass: %p: is known object obj%d\n", ecsArgInfo->get(argOrdinal), argument->getSymbolReference()->getKnownObjectIndex());5645}5646}5647}56485649} // for each arg56505651return;56525653} // checkForConstClass56545655//@TODO this can be re-used as we start building prexargs for every callsite5656TR_PrexArgInfo* TR_PrexArgInfo::buildPrexArgInfoForMethodSymbol(TR::ResolvedMethodSymbol* methodSymbol, TR_LogTracer* tracer)5657{5658int numArgs = methodSymbol->getParameterList().getSize();5659TR_ResolvedMethod *feMethod = methodSymbol->getResolvedMethod();5660ListIterator<TR::ParameterSymbol> parms(&methodSymbol->getParameterList());56615662TR::Compilation *comp = tracer->comp();56635664TR_PrexArgInfo *argInfo = new (comp->trHeapMemory()) TR_PrexArgInfo(numArgs, comp->trMemory());5665heuristicTrace(tracer, "PREX-CSI: Populating parmInfo of current method %s\n", feMethod->signature(comp->trMemory()));5666int index = 0;5667/**5668* For non-static method, first slot of the paramters is populated with the class owning the method. Most of the time,5669* we should be able to get the class pointer using class signature but in case of hidden classes which according to5670* JEP 371, cannot be used directly by bytecode instructions in other classes also is not possible to refer to them in5671* paramters except for the method from the same hidden class. In any case, for non-static methods instead of making5672* VM query to get the owning class, extract that information from resolvedMethod.5673*/5674for (TR::ParameterSymbol *p = parms.getFirst(); p != NULL; index++, p = parms.getNext())5675{5676TR_ASSERT(index < numArgs, "out of bounds!");5677int32_t len = 0;5678const char *sig = p->getTypeSignature(len);56795680if (*sig == 'L' || *sig == 'Q')5681{5682TR_OpaqueClassBlock *clazz = (index == 0 && !methodSymbol->isStatic()) ? feMethod->containingClass() : comp->fe()->getClassFromSignature(sig, len, feMethod);5683if (clazz)5684{5685argInfo->set(index, new (comp->trHeapMemory()) TR_PrexArgument(TR_PrexArgument::ClassIsPreexistent, clazz));5686heuristicTrace(tracer, "PREX-CSI: Parm %d class %p in %p is %.*s\n", index, argInfo->get(index)->getClass(), argInfo->get(index), len, sig);5687}5688}5689}5690return argInfo;5691}569256935694static void populateClassNameSignature(TR::Method *m, TR_ResolvedMethod* caller, TR_OpaqueClassBlock* &c, char* &nc, int32_t &nl, char* &sc, int32_t &sl)5695{5696int32_t len = m->classNameLength();5697char* cs = TR::Compiler->cls.classNameToSignature(m->classNameChars(), len, TR::comp());5698c = caller->fe()->getClassFromSignature(cs, len, caller);5699nc = m->nameChars();5700nl = m->nameLength();5701sc = m->signatureChars();5702sl = m->signatureLength();5703}57045705static char* classSignature (TR::Method * m, TR::Compilation* comp) //tracer helper5706{5707int32_t len = m->classNameLength();5708return TR::Compiler->cls.classNameToSignature(m->classNameChars(), len /*don't care, cos this gives us a null terminated string*/, comp);5709}57105711static bool treeMatchesCallSite(TR::TreeTop* tt, TR::ResolvedMethodSymbol* callerSymbol, TR_CallSite* callsite, TR_LogTracer* tracer)5712{5713if (tt->getNode()->getNumChildren()>0 &&5714tt->getNode()->getFirstChild()->getOpCode().isCall() &&5715tt->getNode()->getFirstChild()->getByteCodeIndex() == callsite->_bcInfo.getByteCodeIndex())5716{5717TR::Node* callNode = tt->getNode()->getFirstChild();57185719TR::MethodSymbol* callNodeMS = callNode->getSymbolReference()->getSymbol()->castToMethodSymbol();5720TR_ASSERT(callNodeMS, "isCall returned true!");57215722if (callNodeMS->isHelper())5723{5724return false;5725}57265727TR_OpaqueClassBlock *callSiteClass, *callNodeClass;57285729char *callSiteNameChars, *callNodeNameChars,5730*callSiteSignatureChars, *callNodeSignatureChars;57315732int32_t callSiteNameLength, callNodeNameLength,5733callSiteSignatureLength, callNodeSignatureLength;573457355736populateClassNameSignature (callsite->_initialCalleeMethod ?5737callsite->_initialCalleeMethod->convertToMethod() : //TR_ResolvedMethod doesn't extend TR::Method5738callsite->_interfaceMethod,5739callerSymbol->getResolvedMethod(),5740callSiteClass,5741callSiteNameChars, callSiteNameLength,5742callSiteSignatureChars, callSiteSignatureLength5743);574457455746populateClassNameSignature (callNodeMS->getMethod(),5747callerSymbol->getResolvedMethod(),5748callNodeClass,5749callNodeNameChars, callNodeNameLength,5750callNodeSignatureChars, callNodeSignatureLength5751);5752575357545755//make sure classes are compatible57565757if (!callNodeClass || !callSiteClass || callerSymbol->getResolvedMethod()->fe()->isInstanceOf (callNodeClass, callSiteClass, true, true, true) != TR_yes)5758{5759if (tracer->heuristicLevel())5760{5761TR::Compilation* comp = TR::comp(); //won't be evaluated unless tracing is on5762heuristicTrace(tracer, "ARGS PROPAGATION: Incompatible classes: callSiteClass %p (%s) callNodeClass %p (%s)",5763callSiteClass,5764classSignature(callsite->_initialCalleeMethod ?5765callsite->_initialCalleeMethod->convertToMethod() :5766callsite->_interfaceMethod,5767comp),5768callNodeClass,5769classSignature(callNodeMS->getMethod(), comp)5770);5771}5772return false;5773}57745775//compare names and signatures5776if (callSiteNameLength != callNodeNameLength ||5777strncmp(callSiteNameChars, callNodeNameChars, callSiteNameLength) ||5778callSiteSignatureLength != callNodeSignatureLength ||5779strncmp(callSiteSignatureChars, callNodeSignatureChars, callSiteSignatureLength))5780{5781heuristicTrace(tracer, "ARGS PROPAGATION: Signature mismatch: callSite class %.*s callNode class %.*s",5782callSiteNameLength, callSiteNameChars, callNodeNameLength, callNodeNameChars);5783return false;5784}57855786//heuristicTrace(tracer, "ARGS PROPAGATION: matched the node!!!");5787return true;5788}57895790return false;5791}57925793TR::TreeTop* TR_PrexArgInfo::getCallTree(TR::ResolvedMethodSymbol* methodSymbol, TR_CallSite* callsite, TR_LogTracer* tracer)5794{5795if (callsite->_callNodeTreeTop)5796return callsite->_callNodeTreeTop;57975798for (TR::TreeTop* tt = methodSymbol->getFirstTreeTop(); tt; tt=tt->getNextTreeTop())5799{5800if (treeMatchesCallSite(tt, methodSymbol, callsite, tracer))5801return tt;5802}58035804heuristicTrace(tracer, "ARGS PROPAGATION: Couldn't find a matching node for callsite %p bci %d", callsite, callsite->_bcInfo.getByteCodeIndex());5805return NULL;5806}58075808TR::Node* TR_PrexArgInfo::getCallNode(TR::ResolvedMethodSymbol* methodSymbol, TR_CallSite* callsite, TR_LogTracer* tracer)5809{5810if (callsite->_callNode)5811return callsite->_callNode;58125813for (TR::TreeTop* tt = methodSymbol->getFirstTreeTop(); tt; tt=tt->getNextTreeTop())5814{5815if (treeMatchesCallSite(tt, methodSymbol, callsite, tracer))5816return tt->getNode()->getFirstChild();5817}58185819heuristicTrace(tracer, "ARGS PROPAGATION: Couldn't find a matching node for callsite %p bci %d", callsite, callsite->_bcInfo.getByteCodeIndex());5820return NULL;5821}58225823bool TR_PrexArgInfo::hasArgInfoForChild (TR::Node *child, TR_PrexArgInfo * argInfo)5824{5825if (child->getOpCode().hasSymbolReference() &&5826child->getSymbolReference()->getSymbol()->isParm() &&5827child->getSymbolReference()->getSymbol()->getParmSymbol()->getOrdinal() < argInfo->getNumArgs() &&5828argInfo->get(child->getSymbolReference()->getSymbol()->getParmSymbol()->getOrdinal()))5829return true;583058315832return false;5833}58345835TR_PrexArgument* TR_PrexArgInfo::getArgForChild(TR::Node *child, TR_PrexArgInfo* argInfo)5836{5837TR_ASSERT(child->getOpCode().hasSymbolReference() &&5838child->getSymbolReference()->getSymbol()->isParm() &&5839child->getSymbolReference()->getSymbol()->getParmSymbol()->getOrdinal() < argInfo->getNumArgs() && argInfo->get(child->getSymbolReference()->getSymbol()->getParmSymbol()->getOrdinal())5840, "hasArgInfoForChild should have returned false");58415842return argInfo->get(child->getSymbolReference()->getSymbol()->getParmSymbol()->getOrdinal());5843}58445845void TR_PrexArgInfo::propagateReceiverInfoIfAvailable (TR::ResolvedMethodSymbol* methodSymbol, TR_CallSite* callsite,5846TR_PrexArgInfo * argInfo, TR_LogTracer *tracer)5847{5848//this implies we have some argInfo available5849TR_ASSERT(argInfo, "otherwise we shouldn't even peek");5850TR::Node* callNode = TR_PrexArgInfo::getCallNode(methodSymbol, callsite, tracer);5851TR::Compilation *comp = tracer->comp();5852heuristicTrace(tracer, "ARGS PROPAGATION: trying to propagate receiver's info for callsite %p at %p", callsite, callNode);5853if (!callNode || comp->getOption(TR_DisableInlinerArgsPropagation))5854return;58555856uint32_t numOfArgs = callNode->getNumChildren()-callNode->getFirstArgumentIndex();58575858if (numOfArgs<1)5859return;5860//TR_ASSERT(numOfArgs > 0, "argsinfo index out of bounds");58615862TR::Node* child = callNode->getChild(callNode->getFirstArgumentIndex());58635864if (TR_PrexArgInfo::hasArgInfoForChild(child, argInfo))5865{5866heuristicTrace(tracer, "ARGS PROPAGATION: the receiver for callsite %p is also one of the caller's args", callsite);5867callsite->_ecsPrexArgInfo = new (comp->trHeapMemory()) TR_PrexArgInfo(numOfArgs, comp->trMemory());5868callsite->_ecsPrexArgInfo->set(0, TR_PrexArgInfo::getArgForChild(child, argInfo));5869}5870}58715872bool TR_PrexArgInfo::validateAndPropagateArgsFromCalleeSymbol(TR_PrexArgInfo* argsFromSymbol, TR_PrexArgInfo* argsFromTarget, TR_LogTracer *tracer)5873{5874if (!argsFromSymbol || !argsFromTarget || tracer->comp()->getOption(TR_DisableInlinerArgsPropagation))5875{5876heuristicTrace(tracer, "ARGS PROPAGATION: argsFromSymbol %p or argsFromTarget %p are missing\n", argsFromSymbol, argsFromTarget);5877return true;5878}58795880heuristicTrace(tracer, "ARGS PROPAGATION: argsFromSymbol (from calleeSymbol)");5881if (tracer->heuristicLevel())5882argsFromSymbol->dumpTrace();58835884//validation5885TR_FrontEnd* fe = tracer->comp()->fe();5886int32_t numArgsToEnhance = std::min(argsFromTarget->getNumArgs(), argsFromSymbol->getNumArgs());5887for (int32_t i = 0; i < numArgsToEnhance; i++)5888{5889if (!argsFromTarget->get(i) || !argsFromTarget->get(i)->getClass()) //no incoming class info5890continue;58915892if (!argsFromSymbol->get(i) || !argsFromSymbol->get(i)->getClass())5893{5894heuristicTrace(tracer, "ARGS PROPAGATION: No class info for arg %d from symbol. ", i);5895return false; //TODO: This can be relaxed5896//just make a copy of incoming args5897//and clear the info for this particular slot5898}58995900/*5901At this point class types from argsFromSymbol and argsFromTarget MUST be compatible5902Incompatibility might mean that we are inlining dead code5903*/5904if (fe->isInstanceOf(argsFromSymbol->get(i)->getClass(), argsFromTarget->get(i)->getClass(), true, true, true) != TR_yes &&5905fe->isInstanceOf(argsFromTarget->get(i)->getClass(), argsFromSymbol->get(i)->getClass(), true, true, true) != TR_yes)5906{5907return false;5908}5909}591059115912TR_PrexArgInfo::enhance(argsFromTarget, argsFromSymbol, tracer->comp()); //otherwise just pick more specific59135914heuristicTrace(tracer, "ARGS PROPAGATION: final argInfo after merging argsFromTarget %p", argsFromTarget);5915if (tracer->heuristicLevel())5916argsFromTarget->dumpTrace();59175918return true;5919}592059215922void TR_PrexArgInfo::clearArgInfoForNonInvariantArguments(TR::ResolvedMethodSymbol* methodSymbol, TR_LogTracer* tracer)5923{5924if (tracer->comp()->getOption(TR_DisableInlinerArgsPropagation))5925return;59265927bool cleanedAnything = false;5928for (TR::TreeTop * tt = methodSymbol->getFirstTreeTop(); tt; tt = tt->getNextTreeTop())5929{5930TR::Node* storeNode = tt->getNode()->getStoreNode();593159325933if (!storeNode || !storeNode->getSymbolReference()->getSymbol()->isParm())5934continue;59355936TR_ASSERT(storeNode->getSymbolReference(), "stores should have symRefs");5937TR::ParameterSymbol* parmSymbol = storeNode->getSymbolReference()->getSymbol()->getParmSymbol();5938if (parmSymbol->getOrdinal() < getNumArgs())5939{5940debugTrace(tracer, "ARGS PROPAGATION: unsetting an arg [%i] of argInfo %p", parmSymbol->getOrdinal(), this);5941set(parmSymbol->getOrdinal(), NULL);5942cleanedAnything = true;5943}5944}59455946if (cleanedAnything)5947{5948debugTrace(tracer, "ARGS PROPAGATION: argInfo %p after clear arg info for non-invariant arguments", this);5949if (tracer->heuristicLevel())5950dumpTrace();5951}5952}59535954void TR_PrexArgInfo::propagateArgsFromCaller(TR::ResolvedMethodSymbol* methodSymbol, TR_CallSite* callsite,5955TR_PrexArgInfo * argInfo, TR_LogTracer *tracer)5956{5957if (tracer->comp()->getOption(TR_DisableInlinerArgsPropagation))5958return;59595960TR_ASSERT(argInfo, "otherwise we shouldn't even peek");5961TR::Node* callNode = TR_PrexArgInfo::getCallNode(methodSymbol, callsite, tracer);5962heuristicTrace(tracer, "ARGS PROPAGATION: trying to propagate arg info from caller symbol to callsite %p at %p", callsite, callNode);59635964if (!callNode)5965return;59665967//If we are dealing with indirect calls, temporary use callsite->_ecsPrexArgInfo->get(0)5968//instead of argInfo->get(0). This is because the former might have been reseted by5969//findCallSiteTarget if it couldn't use argInfo->get(0).5970//In such case, propagating argInfo->get(0) any longer might be incorrect.59715972TR_PrexArgument* receiverPrexArg = NULL;5973TR::Node *receiverChild = callNode->getChild(callNode->getFirstArgumentIndex());5974if (callsite->_ecsPrexArgInfo)5975{5976if (TR_PrexArgInfo::hasArgInfoForChild(receiverChild, argInfo))5977{5978receiverPrexArg = TR_PrexArgInfo::getArgForChild(receiverChild, argInfo);5979argInfo->set(receiverChild->getSymbolReference()->getSymbol()->getParmSymbol()->getOrdinal(), callsite->_ecsPrexArgInfo->get(0));5980}5981}59825983heuristicTrace(tracer, "ARGS PROPAGATION: argsFromTarget before args propagation");5984for (int i = 0; i < callsite->numTargets(); i++)5985if (tracer->heuristicLevel())5986callsite->getTarget(i)->_ecsPrexArgInfo->dumpTrace();59875988for (int i = callNode->getFirstArgumentIndex(); i < callNode->getNumChildren(); i++)5989{5990TR::Node* child = callNode->getChild(i);5991if (TR_PrexArgInfo::hasArgInfoForChild(child, argInfo))5992{5993heuristicTrace(tracer, "ARGS PROPAGATION: arg %d at callsite %p matches caller's arg %d", i, callsite, child->getSymbolReference()->getSymbol()->getParmSymbol()->getOrdinal());59945995for (int j = 0; j < callsite->numTargets(); j++)5996{5997if (!callsite->getTarget(j)->_ecsPrexArgInfo)5998continue;59996000TR_PrexArgInfo* targetArgInfo = callsite->getTarget(j)->_ecsPrexArgInfo;60016002if (i - callNode->getFirstArgumentIndex() >= targetArgInfo->getNumArgs())6003continue;60046005if (!targetArgInfo->get(i - callNode->getFirstArgumentIndex()))6006targetArgInfo->set(i - callNode->getFirstArgumentIndex(), TR_PrexArgInfo::getArgForChild(child, argInfo));6007}6008}6009}60106011// Call checkForConstClass on each target so that uses of constant classes6012// are identified. (The information will be used by applyArgumentHeuristics)6013for (int j = 0; j < callsite->numTargets(); j++)6014{6015TR_J9InlinerUtil::checkForConstClass(callsite->getTarget(j), tracer);6016}60176018//Restoring argInfo (see setting receiverPrexArg above)6019if (receiverPrexArg)6020{6021argInfo->set(receiverChild->getSymbolReference()->getSymbol()->getParmSymbol()->getOrdinal(), receiverPrexArg);6022}60236024if (tracer->heuristicLevel())6025{6026heuristicTrace(tracer, "ARGS PROPAGATION: ArgInfo after propagating the args from the caller");6027for (int i = 0; i < callsite->numTargets(); i++)6028callsite->getTarget(i)->_ecsPrexArgInfo->dumpTrace();6029}6030}60316032void6033TR_J9InlinerUtil::refineColdness(TR::Node* node, bool& isCold)6034{6035bool inlineableJNI = false;6036TR::SymbolReference * symRef = node->getSymbolReference();6037if(symRef->getSymbol()->isResolvedMethod()6038&& symRef->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod())6039inlineableJNI = static_cast<TR_J9InlinerPolicy*>(inliner()->getPolicy())->isInlineableJNI(symRef->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod(),node);60406041isCold = isCold && !inlineableJNI;6042}60436044void6045TR_J9InlinerUtil::computeMethodBranchProfileInfo (TR::Block * cfgBlock, TR_CallTarget* calltarget, TR::ResolvedMethodSymbol* callerSymbol)6046{6047if (cfgBlock) //isn't this equal to genILSucceeded??6048{60496050TR::ResolvedMethodSymbol * calleeSymbol = calltarget->_calleeSymbol;6051TR::TreeTop * callNodeTreeTop = calltarget->_myCallSite->_callNodeTreeTop;60526053TR_MethodBranchProfileInfo *mbpInfo = TR_MethodBranchProfileInfo::getMethodBranchProfileInfo(cfgBlock->getEntry()->getNode()->getInlinedSiteIndex(), comp());6054if (!mbpInfo)6055{6056TR::Block *block = callNodeTreeTop->getEnclosingBlock();60576058mbpInfo = TR_MethodBranchProfileInfo::addMethodBranchProfileInfo (cfgBlock->getEntry()->getNode()->getInlinedSiteIndex(), comp());60596060calleeSymbol->getFlowGraph()->computeInitialBlockFrequencyBasedOnExternalProfiler(comp());6061uint32_t firstBlockFreq = calleeSymbol->getFlowGraph()->getInitialBlockFrequency();60626063int32_t blockFreq = block->getFrequency();6064if (blockFreq < 0)6065blockFreq = 6;60666067float freqScaleFactor = 0.0;6068if (callerSymbol->getFirstTreeTop()->getNode()->getBlock()->getFrequency() > 0)6069{6070freqScaleFactor = (float)(blockFreq)/callerSymbol->getFirstTreeTop()->getNode()->getBlock()->getFrequency();6071if (callerSymbol->getFlowGraph()->getInitialBlockFrequency() > 0)6072freqScaleFactor *= (float)(callerSymbol->getFlowGraph()->getInitialBlockFrequency())/(float)firstBlockFreq;6073}6074mbpInfo->setInitialBlockFrequency(firstBlockFreq);6075mbpInfo->setCallFactor(freqScaleFactor);60766077calleeSymbol->getFlowGraph()->setFrequencies();60786079if (comp()->getOption(TR_TraceBFGeneration))6080{6081traceMsg(comp(), "Setting initial block count for a call with index %d to be %d, call factor %f where block %d (%p) and blockFreq = %d\n", cfgBlock->getEntry()->getNode()->getInlinedSiteIndex(), firstBlockFreq, freqScaleFactor, block->getNumber(), block, blockFreq);6082traceMsg(comp(), "first block freq %d and initial block freq %d\n", callerSymbol->getFirstTreeTop()->getNode()->getBlock()->getFrequency(), callerSymbol->getFlowGraph()->getInitialBlockFrequency());6083}6084}6085}6086}60876088TR_TransformInlinedFunction *6089TR_J9InlinerUtil::getTransformInlinedFunction(TR::ResolvedMethodSymbol *callerSymbol, TR::ResolvedMethodSymbol *calleeSymbol, TR::Block *blockContainingTheCall, TR::TreeTop *callNodeTreeTop,6090TR::Node *callNode, TR_ParameterToArgumentMapper & pam, TR_VirtualGuardSelection *guard, List<TR::SymbolReference> & tempList,6091List<TR::SymbolReference> & availableTemps, List<TR::SymbolReference> & availableBasicBlockTemps)6092{6093return new (comp()->trStackMemory()) TR_J9TransformInlinedFunction(comp(), tracer(), callerSymbol, calleeSymbol, blockContainingTheCall, callNodeTreeTop, callNode, pam, guard, tempList, availableTemps, availableBasicBlockTemps);6094}60956096TR_J9TransformInlinedFunction::TR_J9TransformInlinedFunction(6097TR::Compilation *c, TR_InlinerTracer *tracer,TR::ResolvedMethodSymbol * callerSymbol, TR::ResolvedMethodSymbol * calleeSymbol,6098TR::Block * callNodeBlock, TR::TreeTop * callNodeTreeTop, TR::Node * callNode,6099TR_ParameterToArgumentMapper & mapper, TR_VirtualGuardSelection *guard,6100List<TR::SymbolReference> & temps, List<TR::SymbolReference> & availableTemps,6101List<TR::SymbolReference> & availableTemps2)6102: TR_TransformInlinedFunction(c, tracer, callerSymbol, calleeSymbol, callNodeBlock, callNodeTreeTop, callNode, mapper, guard, temps, availableTemps, availableTemps2)6103{6104}61056106void6107TR_J9TransformInlinedFunction::transform(){6108TR_ResolvedMethod * calleeResolvedMethod = _calleeSymbol->getResolvedMethod();6109if (calleeResolvedMethod->isSynchronized() && !_callNode->canDesynchronizeCall())6110{6111if (comp()->trace(OMR::inlining))6112traceMsg(comp(), "Wrapping in try region for synchronized method\n");6113transformSynchronizedMethod(calleeResolvedMethod);6114}6115TR_TransformInlinedFunction::transform();6116}61176118void6119TR_J9TransformInlinedFunction::transformSynchronizedMethod(TR_ResolvedMethod * calleeMethod)6120{6121// If an inlined synchronized method ends with a throw then we have to unlock the monitor.6122// The stack unwinder does this if the function isn't inlined, but the unwinder doesn't know6123// about the inlined version (unless or until we enhance the meta data).6124// If we change to use the meta data, care must be taken since some call6125// sites may have been desynchronized even though the method is marked as6126// synchronized.6127//6128wrapCalleeInTryRegion(true, false, calleeMethod);6129}61306131void6132TR_J9TransformInlinedFunction::wrapCalleeInTryRegion(bool isSynchronized, bool putCatchInCaller, TR_ResolvedMethod * calleeMethod)6133{6134TR_InlinerDelimiter delimiter(tracer(),"tif.wrapCalleeInTryRegion");6135int32_t handlerIndex = calleeMethod->numberOfExceptionHandlers();6136TR::TreeTop * prevTreeTop = _calleeSymbol->getLastTreeTop(), * originalLastTreeTop = prevTreeTop;61376138TR::CFG *calleeCFG = _calleeSymbol->getFlowGraph();6139TR::Block *catchBlock = NULL;6140TR::Block *block = NULL;6141TR_ScratchList<TR::Block> newCatchBlocks(trMemory());61426143TR_CatchBlockProfileInfo * catchInfo = TR_CatchBlockProfileInfo::get(comp());6144if (catchInfo && catchInfo->getCatchCounter() >= TR_CatchBlockProfileInfo::EDOThreshold)6145{6146// For each explicit throw in the callee add an explicit catch block so that we have a chance6147// of converting throws to gotos.6148//6149for (TR::TreeTop * tt = _calleeSymbol->getFirstTreeTop(); tt != originalLastTreeTop; tt = tt->getNextTreeTop())6150{6151TR::Node * node = tt->getNode();6152if (node->getOpCodeValue() == TR::BBStart)6153block = node->getBlock();6154else if (node->getNumChildren() > 0 &&6155(node = node->getFirstChild())->getOpCodeValue() == TR::athrow &&6156(node = node->getFirstChild())->getOpCodeValue() == TR::New &&6157(node = node->getFirstChild())->getOpCodeValue() == TR::loadaddr &&6158node->getSymbol()->isClassObject() && !node->getSymbolReference()->isUnresolved())6159{6160TR::SymbolReference * symRef = node->getSymbolReference();6161int32_t catchBlockHandler = handlerIndex++;6162prevTreeTop = createThrowCatchBlock(isSynchronized, putCatchInCaller, calleeCFG, block, prevTreeTop, symRef, catchBlockHandler, newCatchBlocks);6163}6164}6165}61666167if (isSynchronized)6168catchBlock = appendCatchBlockForInlinedSyncMethod(calleeMethod, prevTreeTop, 0, handlerIndex);6169else6170catchBlock = appendCatchBlockToRethrowException(calleeMethod, prevTreeTop, putCatchInCaller, 0, handlerIndex, true);61716172TR::Block * monEnterBlock = _calleeSymbol->getFirstTreeTop()->getNode()->getBlock();6173for (TR::CFGNode * n = calleeCFG->getFirstNode(); n; n = n->getNext())6174if (!catchBlock->hasSuccessor(n) &&6175(!isSynchronized || (n != monEnterBlock && !isSyncReturnBlock(comp(), toBlock(n)))) &&6176!toBlock(n)->isOSRCodeBlock() &&6177!toBlock(n)->isOSRCatchBlock())6178calleeCFG->addExceptionEdge(n, catchBlock);61796180// now add the catch blocks (important to do it here so that the above iterator doesn't find these blocks)6181calleeCFG->addNode(catchBlock);61826183ListIterator<TR::Block> bi(&newCatchBlocks);6184for (TR::Block * b = bi.getFirst(); b; b = bi.getNext())6185calleeCFG->addNode(b);61866187if (comp()->trace(OMR::inlining))6188comp()->dumpMethodTrees("Callee Trees", _calleeSymbol);6189}61906191TR::TreeTop *6192TR_J9TransformInlinedFunction::createThrowCatchBlock(bool isSynchronized, bool putCatchInCaller,6193TR::CFG *calleeCFG, TR::Block *block, TR::TreeTop *prevTreeTop,6194TR::SymbolReference *symRef, int32_t handlerIndex,6195TR_ScratchList<TR::Block> & newCatchBlocks)6196{6197TR_InlinerDelimiter delimiter(tracer(),"tif.createThrowCatchBlock");6198TR::Block *catchBlock;6199if (isSynchronized)6200{6201catchBlock = appendCatchBlockForInlinedSyncMethod(6202symRef->getOwningMethod(comp()), prevTreeTop, symRef->getCPIndex(), handlerIndex, false);6203catchBlock->setSpecializedDesyncCatchBlock();6204catchBlock->setIsSynchronizedHandler();6205}6206else6207catchBlock = appendCatchBlockToRethrowException(6208symRef->getOwningMethod(comp()), prevTreeTop, putCatchInCaller, symRef->getCPIndex(), handlerIndex, false);62096210TR::TreeTop *lastRealTree = catchBlock->getLastRealTreeTop();6211if (!lastRealTree->getNode()->getOpCode().isBranch()) // if !isSynchronized, this condition will be true6212prevTreeTop = catchBlock->getExit();6213else6214{6215TR::Block *monexitBlock = catchBlock->getExit()->getNextTreeTop()->getNode()->getBlock();6216TR::Block *rethrowBlock = lastRealTree->getNode()->getBranchDestination()->getNode()->getBlock();6217prevTreeTop = rethrowBlock->getExit();6218newCatchBlocks.add(monexitBlock);6219newCatchBlocks.add(rethrowBlock);6220}6221calleeCFG->addExceptionEdge(block, catchBlock);6222newCatchBlocks.add(catchBlock);62236224return prevTreeTop;6225}62266227TR::Block *6228TR_J9TransformInlinedFunction::appendCatchBlockToRethrowException(6229TR_ResolvedMethod * calleeMethod, TR::TreeTop * prevTreeTop, bool putCatchInCaller, int32_t catchType, int32_t handlerIndex, bool addBlocks)6230{6231TR_InlinerDelimiter delimiter(tracer(),"tif.appendCatchBlockToRethrowException");6232TR::SymbolReferenceTable * symRefTab = comp()->getSymRefTab();62336234TR::Node *modelNode;6235if (putCatchInCaller)6236modelNode = _callNode;6237else6238modelNode = _calleeSymbol->getFirstTreeTop()->getNode();6239//TR::Node * lastNode = prevTreeTop->getNode();62406241TR::Block * catchBlock = TR::Block::createEmptyBlock(modelNode, comp());6242catchBlock->setHandlerInfo(catchType, (uint8_t)comp()->getInlineDepth(), handlerIndex, calleeMethod, comp());62436244if (comp()->getOption(TR_EnableThisLiveRangeExtension))6245{6246if (!_calleeSymbol->isStatic() &&6247(!comp()->fej9()->isClassFinal(_calleeSymbol->getResolvedMethod()->containingClass()) ||6248comp()->fej9()->hasFinalizer(_calleeSymbol->getResolvedMethod()->containingClass())))6249{6250TR::Node *anchoredThis = TR::Node::createWithSymRef(modelNode, TR::aload, 0, symRefTab->findOrCreateAutoSymbol(_calleeSymbol, 0, TR::Address));6251TR::SymbolReference *tempSymRef = comp()->getSymRefTab()->findOrCreateThisRangeExtensionSymRef(_calleeSymbol);6252TR::TreeTop *storeTT = TR::TreeTop::create(comp(), TR::Node::createStore(tempSymRef, anchoredThis));6253catchBlock->append(storeTT);6254}6255}62566257// rethrow the exception6258//6259TR::SymbolReference * tempSymRef = 0;6260TR::Node * loadExcpSymbol = TR::Node::createWithSymRef(modelNode, TR::aload, 0, symRefTab->findOrCreateExcpSymbolRef());6261catchBlock->append(TR::TreeTop::create(comp(), TR::Node::createWithSymRef(TR::athrow, 1, 1, loadExcpSymbol, symRefTab->findOrCreateAThrowSymbolRef(_calleeSymbol))));62626263TR::CFG * calleeCFG = _calleeSymbol->getFlowGraph();6264calleeCFG->addEdge(catchBlock, calleeCFG->getEnd());62656266prevTreeTop->join(catchBlock->getEntry());6267return catchBlock;6268}6269// } RTSJ Support ends62706271TR::Block *6272TR_J9TransformInlinedFunction::appendCatchBlockForInlinedSyncMethod(6273TR_ResolvedMethod * calleeResolvedMethod, TR::TreeTop * prevTreeTop, int32_t catchType, int32_t handlerIndex, bool addBlocks)6274{6275TR_InlinerDelimiter delimiter(tracer(),"tif.appendCatchBlockForInlinedSyncMethod");6276TR::SymbolReferenceTable * symRefTab = comp()->getSymRefTab();62776278TR::Node * lastNode = _calleeSymbol->getFirstTreeTop()->getNode(); //prevTreeTop->getNode();6279TR::Block * catchBlock = TR::Block::createEmptyBlock(lastNode, comp());6280catchBlock->setHandlerInfo(catchType, (uint8_t)comp()->getInlineDepth(), handlerIndex, calleeResolvedMethod, comp());6281catchBlock->setIsSynchronizedHandler();6282catchBlock->setIsSyntheticHandler();62836284// store the exception symbol into a temp6285//6286TR::SymbolReference * tempSymRef = 0;6287TR::Node * excpSymbol = TR::Node::createWithSymRef(lastNode, TR::aload, 0, symRefTab->findOrCreateExcpSymbolRef());6288OMR_InlinerUtil::storeValueInATemp(comp(), excpSymbol, tempSymRef, catchBlock->getEntry(), _callerSymbol, _tempList, _availableTemps, &_availableTemps2);62896290// unlock the monitor6291//6292TR::Node * monitorArg, *monitorArgHandle;6293if (_calleeSymbol->isStatic())6294{6295monitorArgHandle = TR::Node::createWithSymRef(lastNode, TR::loadaddr, 0,6296symRefTab->findOrCreateClassSymbol (_calleeSymbol, 0, _calleeSymbol->getResolvedMethod()->containingClass()));6297monitorArgHandle = TR::Node::createWithSymRef(TR::aloadi, 1, 1, monitorArgHandle, symRefTab->findOrCreateJavaLangClassFromClassSymbolRef());6298}6299else6300monitorArgHandle = TR::Node::createWithSymRef(lastNode, TR::aload, 0, symRefTab->findOrCreateAutoSymbol(_calleeSymbol, 0, TR::Address));63016302TR::CFG * calleeCFG = _calleeSymbol->getFlowGraph();6303TR::Block *monexitBlock = catchBlock;6304TR::Block *rethrowBlock = catchBlock;6305bool createdStoreForMonitorExit = false;6306if (!_calleeSymbol->isStatic())6307{6308monexitBlock = TR::Block::createEmptyBlock(lastNode, comp());6309rethrowBlock = TR::Block::createEmptyBlock(lastNode, comp());6310if (addBlocks)6311{6312calleeCFG->addNode(monexitBlock);6313calleeCFG->addNode(rethrowBlock);6314}63156316monitorArg = monitorArgHandle;63176318if (!comp()->getOption(TR_DisableLiveMonitorMetadata) &&6319_calleeSymbol->isSynchronised() &&6320_calleeSymbol->getSyncObjectTemp())6321{6322TR::TreeTop *storeTT = TR::TreeTop::create(comp(), (TR::Node::create(lastNode,TR::monexitfence,0)));6323catchBlock->append(storeTT);6324createdStoreForMonitorExit = true;6325}63266327TR::Node *ifNode = TR::Node::createif(TR::ifacmpeq, monitorArg->duplicateTree(), TR::Node::aconst(monitorArg, 0),rethrowBlock->getEntry());6328catchBlock->append(TR::TreeTop::create(comp(), ifNode));6329ifNode->getByteCodeInfo().setDoNotProfile(1);63306331catchBlock->getExit()->join(monexitBlock->getEntry());6332monexitBlock->getExit()->join(rethrowBlock->getEntry());6333calleeCFG->addEdge(monexitBlock, rethrowBlock);6334calleeCFG->addEdge(catchBlock, rethrowBlock);6335calleeCFG->addEdge(catchBlock, monexitBlock);6336}6337else6338monitorArg = monitorArgHandle;633963406341// add the store to track liveMonitors6342//6343if (!comp()->getOption(TR_DisableLiveMonitorMetadata) &&6344!createdStoreForMonitorExit &&6345_calleeSymbol->isSynchronised() &&6346_calleeSymbol->getSyncObjectTemp())6347{6348TR::Node *addrNode = TR::Node::create(monitorArg, TR::iconst, 0, 0);6349TR::TreeTop *storeTT = TR::TreeTop::create(comp(), (TR::Node::create(lastNode,TR::monexitfence,0)));6350monexitBlock->append(storeTT);6351}63526353TR::Node *monexitNode = TR::Node::createWithSymRef(TR::monexit, 1, 1, monitorArg, symRefTab->findOrCreateMonitorExitSymbolRef(_calleeSymbol));6354monexitNode->setSyncMethodMonitor(true);6355monexitBlock->append(TR::TreeTop::create(comp(), monexitNode));63566357if (comp()->getOption(TR_EnableThisLiveRangeExtension))6358{6359if (!_calleeSymbol->isStatic() &&6360(!comp()->fej9()->isClassFinal(_calleeSymbol->getResolvedMethod()->containingClass()) ||6361comp()->fej9()->hasFinalizer(_calleeSymbol->getResolvedMethod()->containingClass())))6362{6363TR::Node *anchoredThis = TR::Node::createWithSymRef(lastNode, TR::aload, 0, symRefTab->findOrCreateAutoSymbol(_calleeSymbol, 0, TR::Address));6364TR::SymbolReference *tempSymRef = comp()->getSymRefTab()->findOrCreateThisRangeExtensionSymRef(_calleeSymbol);6365TR::TreeTop *storeTT = TR::TreeTop::create(comp(), TR::Node::createStore(tempSymRef, anchoredThis));6366monexitBlock->append(storeTT);6367}6368}636963706371// rethrow the exception6372//6373TR::Node * temp = TR::Node::createWithSymRef(lastNode, TR::aload, 0, tempSymRef);6374rethrowBlock->append(TR::TreeTop::create(comp(), TR::Node::createWithSymRef(TR::athrow, 1, 1, temp, symRefTab->findOrCreateThrowUnreportedExceptionSymbolRef(_calleeSymbol))));63756376calleeCFG->addEdge(rethrowBlock, calleeCFG->getEnd());63776378prevTreeTop->join(catchBlock->getEntry());6379return catchBlock;6380}63816382bool6383TR_J9TransformInlinedFunction::isSyncReturnBlock(TR::Compilation *comp, TR::Block * b)6384{6385TR::TreeTop * tt = b->getEntry();6386if (!tt) return false;63876388tt = tt->getNextTreeTop();6389TR::Node * node = tt->getNode();63906391if (node->getOpCode().getOpCodeValue() == TR::monexitfence)6392tt = tt->getNextTreeTop();63936394if (node->getOpCode().isStore() && (node->getSymbolReference() == comp->getSymRefTab()->findThisRangeExtensionSymRef()))6395tt = tt->getNextTreeTop();63966397node = tt->getNode();6398if (node->getOpCodeValue() == TR::treetop || node->getOpCode().isNullCheck())6399node = node->getFirstChild();64006401if (node->getOpCodeValue() != TR::monexit)6402return false;64036404tt = tt->getNextTreeTop();6405if (!tt || !tt->getNode()->getOpCode().isReturn())6406return false;64076408return true;6409}64106411/*6412* if the initialCalleeMethod of this callsite is not overridden, add this method as the target of the callsite6413*/6414bool6415TR_J9InlinerUtil::addTargetIfMethodIsNotOverridenInReceiversHierarchy(TR_IndirectCallSite *callsite)6416{6417TR_PersistentCHTable *chTable = comp()->getPersistentInfo()->getPersistentCHTable();64186419if( !chTable->isOverriddenInThisHierarchy(callsite->_initialCalleeMethod, callsite->_receiverClass, callsite->_vftSlot, comp()) &&6420!comp()->getOption(TR_DisableHierarchyInlining))6421{6422if(comp()->trace(OMR::inlining))6423{6424int32_t len;6425bool isClassObsolete = comp()->getPersistentInfo()->isObsoleteClass((void*)callsite->_receiverClass, comp()->fe());6426if(!isClassObsolete)6427{6428char *s = TR::Compiler->cls.classNameChars(comp(), callsite->_receiverClass, len);6429heuristicTrace(tracer(),"Virtual call to %s is not overridden in the hierarchy of thisClass %*s\n",tracer()->traceSignature(callsite->_initialCalleeMethod), len, s);6430}6431else6432{6433heuristicTrace(tracer(),"Virtual call to %s is not overridden in the hierarchy of thisClass <obsolete class>\n",tracer()->traceSignature(callsite->_initialCalleeMethod));6434}6435}64366437TR_VirtualGuardSelection *guard = (fe()->classHasBeenExtended(callsite->_receiverClass)) ?6438new (comp()->trHeapMemory()) TR_VirtualGuardSelection(TR_HierarchyGuard, TR_MethodTest) :6439new (comp()->trHeapMemory()) TR_VirtualGuardSelection(TR_HierarchyGuard, TR_VftTest, callsite->_receiverClass);6440callsite->addTarget(comp()->trMemory(),inliner(),guard,callsite->_initialCalleeMethod,callsite->_receiverClass,heapAlloc);6441return true;6442}6443return false;6444}64456446int32_t6447TR_J9InlinerUtil::getCallCount(TR::Node *callNode)6448{6449return comp()->fej9()->getIProfilerCallCount(callNode->getByteCodeInfo(), comp());6450}64516452TR_ResolvedMethod*6453TR_J9InlinerUtil::findSingleJittedImplementer(TR_IndirectCallSite *callsite)6454{6455return comp()->getPersistentInfo()->getPersistentCHTable()->findSingleJittedImplementer(callsite->_receiverClass, callsite->_vftSlot, callsite->_callerResolvedMethod, comp(), callsite->_initialCalleeSymbol);6456}64576458bool6459TR_J9InlinerUtil::addTargetIfThereIsSingleImplementer (TR_IndirectCallSite *callsite)6460{6461static bool disableSingleJittedImplementerInlining = feGetEnv("TR_DisableSingleJittedImplementerInlining") ? true : false;6462TR_ResolvedMethod *implementer; // A temp to be used to find an implementer in abstract implementer analysis6463//findSingleJittedImplementer J9Virtual also knows about interfaces needs to be virtual6464if (!disableSingleJittedImplementerInlining && comp()->getMethodHotness() >= hot &&6465(implementer = callsite->findSingleJittedImplementer(inliner())))6466{6467if (comp()->trace(OMR::inlining))6468traceMsg(comp(), "inliner: Abstract method %s currently has a single jitted implementation %s\n",6469inliner()->tracer()->traceSignature(callsite->_initialCalleeMethod), implementer->signature(comp()->trMemory()));64706471if (!comp()->cg()->getSupportsProfiledInlining())6472{6473return false;6474}64756476TR_VirtualGuardSelection *guard;6477if (callsite->_receiverClass && !fe()->classHasBeenExtended(callsite->_receiverClass))6478guard = new (comp()->trHeapMemory()) TR_VirtualGuardSelection(TR_ProfiledGuard, TR_VftTest, implementer->classOfMethod());6479else6480guard = new (comp()->trHeapMemory()) TR_VirtualGuardSelection(TR_ProfiledGuard, TR_MethodTest);6481callsite->addTarget(comp()->trMemory(),inliner(),guard,implementer,implementer->classOfMethod(),heapAlloc);6482return true;6483}6484return false;6485}64866487TR_PrexArgInfo*6488TR_J9InlinerUtil::createPrexArgInfoForCallTarget(TR_VirtualGuardSelection *guard, TR_ResolvedMethod *implementer)6489{6490TR_PrexArgInfo *myPrexArgInfo = NULL;6491//if CSI (context sensitive inlining + args propagation) enabled we still want to create an argInfo for args propagation6492if (!comp()->getOption(TR_DisableInlinerArgsPropagation) && comp()->fej9()->supportsContextSensitiveInlining())6493{6494//rather than sticking in a not-null check in TR_J9EstimateCodeSize::realEstimateCodeSize and duplicating the line below6495//we might as well put a supportsContextSensitiveInlining check in here6496myPrexArgInfo = new (comp()->trHeapMemory()) TR_PrexArgInfo(implementer->numberOfParameters(), comp()->trMemory());6497if( guard->_type == TR_VftTest)6498{64996500TR_ASSERT(implementer, "no implementer!\n");6501TR_ASSERT(!implementer->isStatic(), "method is static\n");65026503myPrexArgInfo->set(0, new (comp()->trHeapMemory()) TR_PrexArgument(TR_PrexArgument::ClassIsFixed, guard->_thisClass));65046505if (tracer()->heuristicLevel())6506{6507int32_t len;6508char *s = TR::Compiler->cls.classNameChars(comp(), guard->_thisClass, len);6509heuristicTrace(tracer(),"Created an argInfo to fix receiver to class %s",s);6510}6511}65126513bool isArchetypeSpecimen =6514implementer->convertToMethod()->isArchetypeSpecimen()6515&& implementer->getMethodHandleLocation() != NULL;65166517bool isMCS = guard->_kind == TR_MutableCallSiteTargetGuard;65186519bool isLambdaFormMCS =6520isMCS && comp()->fej9()->isLambdaFormGeneratedMethod(implementer);65216522if ((isArchetypeSpecimen || isLambdaFormMCS) && comp()->getOrCreateKnownObjectTable())6523{6524TR::KnownObjectTable::Index mhIndex = TR::KnownObjectTable::UNKNOWN;6525if (isLambdaFormMCS)6526{6527mhIndex = guard->_mutableCallSiteEpoch;6528}6529else6530{6531uintptr_t *mhLocation = implementer->getMethodHandleLocation();6532mhIndex = comp()->getKnownObjectTable()->getOrCreateIndexAt(mhLocation);6533}65346535auto prexArg = new (comp()->trHeapMemory()) TR_PrexArgument(mhIndex, comp());6536if (isMCS)6537prexArg->setTypeInfoForInlinedBody();6538myPrexArgInfo->set(0, prexArg);6539}6540}6541return myPrexArgInfo;6542}65436544TR_InnerPreexistenceInfo *6545TR_J9InlinerUtil::createInnerPrexInfo(TR::Compilation * c, TR::ResolvedMethodSymbol *methodSymbol, TR_CallStack *callStack,6546TR::TreeTop *callTree, TR::Node *callNode,6547TR_VirtualGuardKind guardKind)6548{6549return new(comp()->trStackMemory())TR_J9InnerPreexistenceInfo(c, methodSymbol, callStack, callTree, callNode, guardKind);6550}65516552//---------------------------------------------------------------------6553// TR_J9InnerPreexistenceInfo::ParmInfo6554//---------------------------------------------------------------------6555TR_J9InnerPreexistenceInfo::ParmInfo::ParmInfo(TR::ParameterSymbol *innerParm, TR::ParameterSymbol *outerParm)6556: _innerParm(innerParm), _outerParm(outerParm), _isInvariant(true)6557{}65586559bool6560TR_J9InnerPreexistenceInfo::perform(TR::Compilation *comp, TR::Node *guardNode, bool & disableTailRecursion)6561{6562static char *disable = feGetEnv("TR_DisableIPREX");6563if (disable ||6564!comp->getOptimizer()->isEnabled(OMR::innerPreexistence) ||6565comp->getOption(TR_FullSpeedDebug) ||6566comp->getHCRMode() != TR::none ||6567guardNode->isHCRGuard() ||6568guardNode->isBreakpointGuard() ||6569comp->compileRelocatableCode())6570return false;65716572// perform() is a misnomer -- most of the work is already done by the constructor6573// at this stage - we just find what is the best way to utilize the information6574//6575if (!comp->performVirtualGuardNOPing())6576return false;65776578// If we have inner assumptions - then we must register the assumptions on the6579// virtual guard6580//6581if (hasInnerAssumptions())6582{6583TR_VirtualGuard *virtualGuard = comp->findVirtualGuardInfo(guardNode);6584TR_ASSERT(virtualGuard, "Must have an outer guard to have inner assumptions");65856586disableTailRecursion = true;6587ListIterator<TR_InnerAssumption> it(&getInnerAssumptions());6588for (TR_InnerAssumption *a = it.getFirst(); a; a = it.getNext())6589virtualGuard->addInnerAssumption(a);6590}6591else6592{6593// Else, see if we can directly devirtualize this call by using inner preexistence6594//6595TR_VirtualGuard *virtualGuard = comp->findVirtualGuardInfo(guardNode);6596PreexistencePoint *point = getPreexistencePoint(0); // ie. see if the 'this' for the call preexists6597if (point &&6598performTransformation(comp, "%sIPREX: remove virtual guard for inlined call %p to %s because it inner preexists parm ordinal %d of %s\n",6599OPT_DETAILS, _callNode, _methodSymbol->getResolvedMethod()->signature(trMemory()),6600point->_ordinal, point->_callStack->_methodSymbol->getResolvedMethod()->signature(trMemory())))6601{6602TR_ASSERT(virtualGuard, "we cannot directly devirtualize anything thats not guarded");66036604//_callNode->devirtualizeCall(_callTree);66056606// Add an inner assumption on the outer guard6607//6608TR_InnerAssumption *a = new (comp->trHeapMemory()) TR_InnerAssumption(point->_ordinal, virtualGuard);6609((TR_J9InnerPreexistenceInfo *)point->_callStack->_innerPrexInfo)->addInnerAssumption(a);6610disableTailRecursion = true;66116612// Tell compilation that this guard is to be removed6613//6614comp->removeVirtualGuard(virtualGuard);66156616// "Remove" the guard node6617//6618TR_ASSERT(guardNode->getOpCodeValue() == TR::ificmpne ||6619guardNode->getOpCodeValue() == TR::iflcmpne ||6620guardNode->getOpCodeValue() == TR::ifacmpne,6621"Wrong kind of if discovered for a virtual guard");6622guardNode->getFirstChild()->recursivelyDecReferenceCount();6623guardNode->setAndIncChild(0, guardNode->getSecondChild());6624guardNode->resetIsTheVirtualGuardForAGuardedInlinedCall();66256626// FIXME:6627//printf("---$$$--- inner prex in %s\n", comp->signature());66286629((TR::Optimizer*)comp->getOptimizer())->setRequestOptimization(OMR::treeSimplification, true);66306631return true;6632}6633}6634return false;6635}66366637//---------------------------------------------------------------------6638// TR_J9InnerPreexistenceInfo6639//---------------------------------------------------------------------66406641TR_J9InnerPreexistenceInfo::TR_J9InnerPreexistenceInfo(TR::Compilation * c, TR::ResolvedMethodSymbol *methodSymbol,6642TR_CallStack *callStack, TR::TreeTop *treeTop,6643TR::Node *callNode, TR_VirtualGuardKind guardKind)6644:TR_InnerPreexistenceInfo(c, methodSymbol, callStack, treeTop, callNode, guardKind)6645{6646static char *disable = feGetEnv("TR_DisableIPREX");6647if (!c->getOptimizer()->isEnabled(OMR::innerPreexistence) ||6648c->compileRelocatableCode() ||6649disable ||6650!_methodSymbol ||6651c->getHCRMode() == TR::traditional)6652return;66536654_numArgs = methodSymbol->getParameterList().getSize();6655_parameters = (ParmInfo **) trMemory()->allocateStackMemory(_numArgs * sizeof(ParmInfo*));6656memset(_parameters, 0, _numArgs * sizeof(ParmInfo*));66576658// Initialize the Parameter Info Array6659//6660ListIterator<TR::ParameterSymbol> parmIt(&methodSymbol->getParameterList());6661int32_t ordinal = 0;6662for (TR::ParameterSymbol *p = parmIt.getFirst(); p; p = parmIt.getNext(), ordinal++)6663{6664if (p->getDataType() == TR::Address)6665{6666_parameters[ordinal] = new (trStackMemory()) ParmInfo(p);6667}6668}66696670// Walk the IL of the method to find out which parms are invariant6671//6672for (TR::TreeTop *tt = methodSymbol->getFirstTreeTop();6673tt; tt = tt->getNextRealTreeTop())6674{6675TR::Node *node = tt->getNode();6676if (node->getOpCodeValue() == TR::treetop)6677node = node->getFirstChild();66786679if (node->getOpCode().isStoreDirect() && node->getDataType() == TR::Address)6680{6681TR::Symbol *symbol = node->getSymbolReference()->getSymbol();6682if (symbol->isParm())6683{6684getParmInfo(symbol->getParmSymbol()->getOrdinal())->setNotInvariant();6685}6686}6687}66886689// Figure out how the parms of the caller method tie together with the parms6690// of this method6691//6692if (_callNode) // we are being inlined6693{6694TR::Node *node = _callNode;6695TR_ASSERT(callStack, "must have a call stack if we are being inlined from somewhere\n");66966697int32_t firstArgIndex = node->getFirstArgumentIndex();6698for (int32_t c = node->getNumChildren() - 1; c >= firstArgIndex; --c)6699{6700TR::Node *argument = node->getChild(c);6701if (argument->getOpCodeValue() == TR::aload)6702{6703TR::ParameterSymbol *parmSymbol = argument->getSymbolReference()->getSymbol()->getParmSymbol();6704if (parmSymbol && c - firstArgIndex<ordinal)6705{6706ParmInfo *parmInfo = getParmInfo(c - firstArgIndex);6707if (parmInfo) parmInfo->setOuterSymbol(parmSymbol);6708}6709}6710}6711}67126713}67146715TR_J9InnerPreexistenceInfo::PreexistencePoint *6716TR_J9InnerPreexistenceInfo::getPreexistencePoint(int32_t ordinal)6717{6718if (hasInnerAssumptions()) return 0;6719ParmInfo *parmInfo = getParmInfo(ordinal);6720if (!parmInfo->_outerParm) return 0;6721if (!_callStack) return 0;67226723return ((TR_J9InnerPreexistenceInfo *)_callStack->_innerPrexInfo)->getPreexistencePointImpl(parmInfo->_outerParm->getOrdinal(), _callStack);6724}67256726TR_J9InnerPreexistenceInfo::PreexistencePoint *6727TR_J9InnerPreexistenceInfo::getPreexistencePointImpl(int32_t ordinal, TR_CallStack *prevCallStack)6728{6729ParmInfo *parmInfo = getParmInfo(ordinal);6730if (!parmInfo->isInvariant()) return 0;6731if (!_callStack) return 0;67326733PreexistencePoint *point = 0;6734if (parmInfo->_outerParm)6735point = ((TR_J9InnerPreexistenceInfo *)_callStack->_innerPrexInfo)->getPreexistencePointImpl(parmInfo->_outerParm->getOrdinal(), _callStack);67366737if (!point)6738{67396740if (_guardKind != TR_ProfiledGuard && (_guardKind != TR_NoGuard || !comp()->hasIntStreamForEach())) // FIXME: this limitation can be removed by doing the tree transformation6741point = new (trStackMemory()) PreexistencePoint(prevCallStack, ordinal);6742}67436744return point;6745}67466747bool TR_J9InlinerPolicy::dontPrivatizeArgumentsForRecognizedMethod(TR::RecognizedMethod recognizedMethod)6748{6749static char *aggressiveJSR292Opts = feGetEnv("TR_aggressiveJSR292Opts");6750if (aggressiveJSR292Opts && strchr(aggressiveJSR292Opts, '2'))6751{6752switch (recognizedMethod)6753{6754case TR::java_lang_invoke_MethodHandle_invokeExactTargetAddress:6755return true;67566757default:6758break;6759}6760}6761return false;6762}67636764bool6765TR_J9InlinerPolicy::replaceSoftwareCheckWithHardwareCheck(TR_ResolvedMethod *calleeMethod)6766{6767if (calleeMethod && comp()->cg()->getSupportsBDLLHardwareOverflowCheck() &&6768((strncmp(calleeMethod->signature(comp()->trMemory()), "java/math/BigDecimal.noLLOverflowAdd(JJJ)Z", 42) == 0) ||6769(strncmp(calleeMethod->signature(comp()->trMemory()), "java/math/BigDecimal.noLLOverflowMul(JJJ)Z", 42) == 0)))6770return true;6771else return false;6772}67736774bool6775TR_J9InlinerPolicy::suitableForRemat(TR::Compilation *comp, TR::Node *callNode, TR_VirtualGuardSelection *guard)6776{6777float profiledGuardProbabilityThreshold = 0.6f;6778static char *profiledGuardProbabilityThresholdStr = feGetEnv("TR_ProfiledGuardRematProbabilityThreshold");6779if (profiledGuardProbabilityThresholdStr)6780{6781profiledGuardProbabilityThreshold = ((float)atof(profiledGuardProbabilityThresholdStr));6782}67836784bool suitableForRemat = true;6785TR_AddressInfo *valueInfo = static_cast<TR_AddressInfo*>(TR_ValueProfileInfoManager::getProfiledValueInfo(callNode, comp, AddressInfo));6786if (guard->isHighProbablityProfiledGuard())6787{6788if (comp->getMethodHotness() <= warm && comp->getPersistentInfo()->getJitState() == STARTUP_STATE)6789{6790suitableForRemat = false;6791TR::DebugCounter::incStaticDebugCounter(comp, TR::DebugCounter::debugCounterName(comp, "profiledPrivArgRemat/unsuitableForRemat/warmHighProb"));6792}6793else6794{6795TR::DebugCounter::incStaticDebugCounter(comp, TR::DebugCounter::debugCounterName(comp, "profiledPrivArgRemat/suitableForRemat/highProb"));6796}6797}6798else if (valueInfo)6799{6800if (valueInfo->getTopProbability() >= profiledGuardProbabilityThreshold)6801{6802TR::DebugCounter::incStaticDebugCounter(comp, TR::DebugCounter::debugCounterName(comp, "profiledPrivArgRemat/suitableForRemat/probability=%d", ((int32_t)(valueInfo->getTopProbability() * 100))));6803}6804else6805{6806TR::DebugCounter::incStaticDebugCounter(comp, TR::DebugCounter::debugCounterName(comp, "profiledPrivArgRemat/unsuitableForRemat/probability=%d", ((int32_t)(valueInfo->getTopProbability() * 100))));6807suitableForRemat = false;6808}6809}6810else6811{6812TR::DebugCounter::incStaticDebugCounter(comp, TR::DebugCounter::debugCounterName(comp, "profiledPrivArgRemat/unsuitableForRemat/noinfo"));6813suitableForRemat = false;6814}6815return suitableForRemat;6816}68176818TR_J9InlinerTracer::TR_J9InlinerTracer(TR::Compilation *comp, TR_FrontEnd *fe, TR::Optimization *opt)6819: TR_InlinerTracer(comp, fe, opt)6820{}68216822TR_InlinerTracer *6823TR_J9InlinerUtil::getInlinerTracer(TR::Optimization *optimization)6824{6825return new (comp()->trHeapMemory()) TR_J9InlinerTracer(comp(),fe(),optimization);6826}68276828void TR_J9InlinerTracer::dumpProfiledClasses (ListIterator<TR_ExtraAddressInfo>& sortedValuesIt, uint32_t totalFrequency)6829{6830if(heuristicLevel())6831{6832TR_ExtraAddressInfo *profiledInfo;6833for (profiledInfo = sortedValuesIt.getFirst(); profiledInfo != NULL; profiledInfo = sortedValuesIt.getNext())6834{6835int32_t freq = profiledInfo->_frequency;6836TR_OpaqueClassBlock* tempreceiverClass = (TR_OpaqueClassBlock *) profiledInfo->_value;6837float val = (float)freq/(float)totalFrequency;6838int32_t len = 1;6839bool isClassObsolete = comp()->getPersistentInfo()->isObsoleteClass((void*)tempreceiverClass, comp()->fe());68406841if(!isClassObsolete)6842{6843const char *className = TR::Compiler->cls.classNameChars(comp(), tempreceiverClass, len);6844heuristicTrace(this , "receiverClass %s has a profiled frequency of %f", className,val);6845}6846else6847{6848heuristicTrace(this, "receiverClass %p is obsolete and has profiled frequency of %f",tempreceiverClass,val);6849}6850}6851}68526853}685468556856