Path: blob/master/runtime/compiler/optimizer/J9Inliner.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2000, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "optimizer/Inliner.hpp"23#include "optimizer/J9Inliner.hpp"2425#include <algorithm>26#include "env/KnownObjectTable.hpp"27#include "compile/OSRData.hpp"28#include "compile/ResolvedMethod.hpp"29#include "env/CompilerEnv.hpp"30#include "env/CHTable.hpp"31#include "env/PersistentCHTable.hpp"32#include "env/VMJ9.h"33#include "env/jittypes.h"34#include "env/VMAccessCriticalSection.hpp"35#include "il/Block.hpp"36#include "il/Node.hpp"37#include "il/Node_inlines.hpp"38#include "il/ParameterSymbol.hpp"39#include "il/StaticSymbol.hpp"40#include "il/TreeTop.hpp"41#include "il/TreeTop_inlines.hpp"42#include "optimizer/CallInfo.hpp"43#include "optimizer/J9CallGraph.hpp"44#include "optimizer/PreExistence.hpp"45#include "optimizer/RematTools.hpp"46#include "optimizer/Structure.hpp"47#include "runtime/J9Profiler.hpp"48#include "runtime/J9ValueProfiler.hpp"49#include "codegen/CodeGenerator.hpp"50#include "ilgen/J9ByteCode.hpp"51#include "ilgen/J9ByteCodeIterator.hpp"5253#define OPT_DETAILS "O^O INLINER: "54const float MIN_PROFILED_CALL_FREQUENCY = (.65f); // lowered this from .80f since opportunities were being missed in WAS; in those cases getting rid of the call even in 65% of the cases was beneficial probably due to the improved icache impact5556extern int32_t *NumInlinedMethods; // Defined in Inliner.cpp57extern int32_t *InlinedSizes; // Defined in Inliner.cpp585960//duplicated as long as there are two versions of findInlineTargets61static uintptr_t *failMCS(char *reason, TR_CallSite *callSite, TR_InlinerBase* inliner)62{63debugTrace(inliner->tracer()," Fail isMutableCallSiteTargetInvokeExact(%p): %s", callSite, reason);64return NULL;65}6667static uintptr_t *isMutableCallSiteTargetInvokeExact(TR_CallSite *callSite, TR_InlinerBase *inliner)68{69// Looking for either mcs.target.invokeExact(...) or mcs.getTarget().invokeExact(...)70// on some known/fixed MutableCallSite object mcs.71// Return NULL if it's neither of these.7273if (inliner->comp()->getOption(TR_DisableMutableCallSiteGuards))74return NULL;7576TR::Node *callNode = callSite->_callNode;77if (!callNode || !callNode->getOpCode().isCall())78return failMCS("No call node", callSite, inliner);79else if (callNode->getSymbolReference()->isUnresolved())80return failMCS("Call symref is unresolved", callSite, inliner);81else switch (callNode->getSymbol()->castToResolvedMethodSymbol()->getRecognizedMethod())82{83case TR::java_lang_invoke_MethodHandle_invokeExact:84break;85default:86return failMCS("Call symref is not invokeExact", callSite, inliner);87}8889TR::Node *targetNode = callNode->getChild(callNode->getFirstArgumentIndex());90if (!targetNode->getOpCode().hasSymbolReference() || targetNode->getSymbolReference()->isUnresolved())91return failMCS("No target symref", callSite, inliner);9293TR::Node *mcsNode = (TR::Node*)(intptr_t)0xdead;94if (targetNode->getOpCode().isCall())95{96switch (targetNode->getSymbol()->castToResolvedMethodSymbol()->getRecognizedMethod())97{98case TR::java_lang_invoke_MutableCallSite_getTarget:99mcsNode = targetNode->getChild(targetNode->getFirstArgumentIndex());100break;101default:102return failMCS("Call receiver isn't a call to getTarget", callSite, inliner);103}104}105else if (targetNode->getOpCode().isLoadIndirect() && targetNode->getDataType() == TR::Address)106{107switch (targetNode->getSymbol()->getRecognizedField())108{109case TR::Symbol::Java_lang_invoke_MutableCallSite_target:110mcsNode = targetNode->getFirstChild();111break;112default:113return failMCS("Call receiver isn't a load of target field", callSite, inliner);114}115}116else117{118return failMCS("Unsuitable call receiver", callSite, inliner);119}120121if (mcsNode->getSymbolReference()->hasKnownObjectIndex())122{123uintptr_t *result = mcsNode->getSymbolReference()->getKnownObjectReferenceLocation(inliner->comp());124heuristicTrace(inliner->tracer(), " Success: isMutableCallSiteTargetInvokeExact(%p)=%p (obj%d)", callSite, result, mcsNode->getSymbolReference()->getKnownObjectIndex());125return result;126}127else if (mcsNode->getSymbol()->isFixedObjectRef())128{129uintptr_t *result = (uintptr_t*)mcsNode->getSymbol()->castToStaticSymbol()->getStaticAddress();130heuristicTrace(inliner->tracer()," Success: isMutableCallSiteTargetInvokeExact(%p)=%p (fixed object reference)", callSite, result);131return result;132}133else134{135return failMCS("Unknown MutableCallSite object", callSite, inliner);136}137}138139140141TR_CallSite* TR_CallSite::create(TR::TreeTop* callNodeTreeTop,142TR::Node *parent,143TR::Node* callNode,144TR_OpaqueClassBlock *receiverClass,145TR::SymbolReference *symRef,146TR_ResolvedMethod *resolvedMethod,147TR::Compilation* comp,148TR_Memory* trMemory,149TR_AllocationKind kind,150TR_ResolvedMethod* caller,151int32_t depth,152bool allConsts)153154{155156TR::MethodSymbol *calleeSymbol = symRef->getSymbol()->castToMethodSymbol();157TR_ResolvedMethod* lCaller = caller ? caller : symRef->getOwningMethod(comp);158159if (callNode->getOpCode().isCallIndirect())160{161if (calleeSymbol->isInterface() )162{163return new (trMemory, kind) TR_J9InterfaceCallSite (lCaller,164callNodeTreeTop,165parent,166callNode,167calleeSymbol->getMethod(),168receiverClass,169(int32_t)symRef->getOffset(),170symRef->getCPIndex(),171resolvedMethod,172calleeSymbol->getResolvedMethodSymbol(),173callNode->getOpCode().isCallIndirect(),174calleeSymbol->isInterface(),175callNode->getByteCodeInfo(),176comp,177depth,178allConsts);179}180else181{182if (calleeSymbol->getResolvedMethodSymbol() &&183calleeSymbol->getResolvedMethodSymbol()->getResolvedMethod()->convertToMethod()->isArchetypeSpecimen() &&184calleeSymbol->getResolvedMethodSymbol()->getResolvedMethod()->getMethodHandleLocation())185{186return new (trMemory, kind) TR_J9MethodHandleCallSite (lCaller,187callNodeTreeTop,188parent,189callNode,190calleeSymbol->getMethod(),191receiverClass,192(int32_t)symRef->getOffset(),193symRef->getCPIndex(),194resolvedMethod,195calleeSymbol->getResolvedMethodSymbol(),196callNode->getOpCode().isCallIndirect(),197calleeSymbol->isInterface(),198callNode->getByteCodeInfo(),199comp,200depth,201allConsts) ;202}203204if (calleeSymbol->getResolvedMethodSymbol() && calleeSymbol->getResolvedMethodSymbol()->getRecognizedMethod() == TR::java_lang_invoke_MethodHandle_invokeExact)205{206return new (trMemory, kind) TR_J9MutableCallSite (lCaller,207callNodeTreeTop,208parent,209callNode,210calleeSymbol->getMethod(),211receiverClass,212(int32_t)symRef->getOffset(),213symRef->getCPIndex(),214resolvedMethod,215calleeSymbol->getResolvedMethodSymbol(),216callNode->getOpCode().isCallIndirect(),217calleeSymbol->isInterface(),218callNode->getByteCodeInfo(),219comp,220depth,221allConsts) ;222}223224return new (trMemory, kind) TR_J9VirtualCallSite (lCaller,225callNodeTreeTop,226parent,227callNode,228calleeSymbol->getMethod(),229receiverClass,230(int32_t)symRef->getOffset(),231symRef->getCPIndex(),232resolvedMethod,233calleeSymbol->getResolvedMethodSymbol(),234callNode->getOpCode().isCallIndirect(),235calleeSymbol->isInterface(),236callNode->getByteCodeInfo(),237comp,238depth,239allConsts) ;240241}242}243244return new (trMemory, kind) TR_DirectCallSite (lCaller,245callNodeTreeTop,246parent,247callNode,248calleeSymbol->getMethod(),249resolvedMethod && !resolvedMethod->isStatic() ? receiverClass : NULL,250(int32_t)symRef->getOffset(),251symRef->getCPIndex(),252resolvedMethod,253calleeSymbol->getResolvedMethodSymbol(),254callNode->getOpCode().isCallIndirect(),255calleeSymbol->isInterface(),256callNode->getByteCodeInfo(),257comp,258depth,259allConsts) ;260261}262263264265static void computeNumLivePendingSlotsAndNestingDepth(TR::Optimizer* optimizer, TR_CallTarget* calltarget, TR_CallStack* callStack, int32_t& numLivePendingPushSlots, int32_t& nestingDepth)266{267TR::Compilation *comp = optimizer->comp();268269if (comp->getOption(TR_EnableOSR))270{271TR::Block *containingBlock = calltarget->_myCallSite->_callNodeTreeTop->getEnclosingBlock();272int32_t weight = 1;273nestingDepth = weight/10;274275TR::Node *callNode = calltarget->_myCallSite->_callNode;276int32_t callerIndex = callNode->getByteCodeInfo().getCallerIndex();277TR::ResolvedMethodSymbol *caller = (callerIndex == -1) ? comp->getMethodSymbol()278: comp->getInlinedResolvedMethodSymbol(callerIndex);279TR_OSRMethodData *osrMethodData = comp->getOSRCompilationData()->findOrCreateOSRMethodData(callerIndex, caller);280TR_Array<List<TR::SymbolReference> > *pendingPushSymRefs = caller->getPendingPushSymRefs();281282int32_t numPendingSlots = 0;283284if (pendingPushSymRefs)285numPendingSlots = pendingPushSymRefs->size();286287TR_BitVector *deadSymRefs = osrMethodData->getLiveRangeInfo(calltarget->_myCallSite->_callNode->getByteCodeIndex());288289for (int32_t i=0;i<numPendingSlots;i++)290{291List<TR::SymbolReference> symRefsAtThisSlot = (*pendingPushSymRefs)[i];292293if (symRefsAtThisSlot.isEmpty()) continue;294295ListIterator<TR::SymbolReference> symRefsIt(&symRefsAtThisSlot);296TR::SymbolReference *nextSymRef;297for (nextSymRef = symRefsIt.getCurrent(); nextSymRef; nextSymRef=symRefsIt.getNext())298{299if (!deadSymRefs || !deadSymRefs->get(nextSymRef->getReferenceNumber()))300numLivePendingPushSlots++;301}302}303304optimizer->comp()->incNumLivePendingPushSlots(numLivePendingPushSlots);305optimizer->comp()->incNumLoopNestingLevels(nestingDepth);306}307}308309/*310* Populate the OSRCallSiteRematTable using the pending push stores before this call.311* To achieve this, RematTools is applied to the pending pushes that correspond to the call,312* however, it is limited to using autos, parms and pending push temps as others may be313* modified within the call.314*/315static void populateOSRCallSiteRematTable(TR::Optimizer* optimizer, TR_CallTarget* calltarget,316TR_CallStack* callStack)317{318static const char *verboseCallSiteRemat = feGetEnv("TR_VerboseOSRCallSiteRemat");319TR::TreeTop *call = calltarget->_myCallSite->_callNodeTreeTop;320TR::ResolvedMethodSymbol *method = callStack->_methodSymbol;321TR::Compilation *comp = optimizer->comp();322TR_ByteCodeInfo &bci = method->getOSRByteCodeInfo(call->getNode());323TR::TreeTop *blockStart = call->getEnclosingBlock()->getFirstRealTreeTop();324325TR::SparseBitVector scanTargets(comp->allocator());326RematSafetyInformation safetyInfo(comp);327TR::list<TR::TreeTop *> failedPP(getTypedAllocator<TR::TreeTop*>(comp->allocator()));328329// Search through all of the PPS for those that can be remated330//331for (332TR::TreeTop *cursor = call->getPrevTreeTop();333cursor && method->isOSRRelatedNode(cursor->getNode(), bci);334cursor = cursor->getPrevTreeTop())335{336TR::Node *store = cursor->getNode();337if (!store->getOpCode().isStoreDirect() || !store->getSymbol()->isPendingPush())338continue;339340TR::Node *child = store->getFirstChild();341// A PPS of an auto/parm. Necessary to scan to check if auto/parm has not been modified342// since it was anchored.343//344int32_t callerIndex = child->getByteCodeInfo().getCallerIndex();345346if (child->getOpCode().hasSymbolReference()347&& (child->getSymbol()->isParm()348|| (child->getSymbol()->isAuto()349&& child->getSymbolReference()->getCPIndex() <350(( (callerIndex == -1) ? comp->getMethodSymbol()351: comp->getInlinedResolvedMethodSymbol(callerIndex) )->getFirstJitTempIndex()))))352{353if (comp->trace(OMR::inlining))354traceMsg(comp, "callSiteRemat: found potential pending push #%d with store #%d\n", store->getSymbolReference()->getReferenceNumber(),355child->getSymbolReference()->getReferenceNumber());356357TR::SparseBitVector symRefsToCheck(comp->allocator());358symRefsToCheck[child->getSymbolReference()->getReferenceNumber()] = true;359scanTargets[child->getGlobalIndex()] = true;360safetyInfo.add(cursor, symRefsToCheck);361}362363// Storing failures, will search for a double store that occurs before364//365else366{367if (comp->trace(OMR::inlining))368traceMsg(comp, "callSiteRemat: failed to find store for pending push #%d\n", store->getSymbolReference()->getReferenceNumber());369370failedPP.push_back(cursor);371}372}373374// Perform search for any double stores375// This goes from the start of the block to the call, as PPs may store376// duplicate values377//378if (failedPP.size() > 0)379RematTools::walkTreeTopsCalculatingRematFailureAlternatives(comp,380blockStart, call, failedPP, scanTargets, safetyInfo, verboseCallSiteRemat != NULL);381382// Perform the safety check, to ensure symrefs haven't been383// modified.384//385TR::SparseBitVector unsafeSymRefs(comp->allocator());386if (!scanTargets.IsZero())387RematTools::walkTreesCalculatingRematSafety(comp, blockStart,388call, scanTargets, unsafeSymRefs, verboseCallSiteRemat != NULL);389390// Perform place those without unsafe symrefs in the remat table391//392for (uint32_t i = 0; i < safetyInfo.size(); ++i)393{394TR::TreeTop *storeTree = safetyInfo.argStore(i);395TR::TreeTop *rematTree = safetyInfo.rematTreeTop(i);396TR::Node *node = rematTree->getNode();397TR::Node *child = node->getFirstChild();398399if (!unsafeSymRefs.Intersects(safetyInfo.symRefDependencies(i)))400{401if (storeTree == rematTree)402{403if (comp->trace(OMR::inlining))404traceMsg(comp, "callSiteRemat: adding pending push #%d with store #%d to remat table\n",405storeTree->getNode()->getSymbolReference()->getReferenceNumber(),406child->getSymbolReference()->getReferenceNumber());407408comp->setOSRCallSiteRemat(comp->getCurrentInlinedSiteIndex(),409storeTree->getNode()->getSymbolReference(),410child->getSymbolReference());411}412else413{414int32_t callerIndex = node->getByteCodeInfo().getCallerIndex();415if (node->getSymbol()->isParm()416|| node->getSymbol()->isPendingPush()417|| (node->getSymbol()->isAuto()418&& node->getSymbolReference()->getCPIndex() <419(( (callerIndex == -1) ? comp->getMethodSymbol()420: comp->getInlinedResolvedMethodSymbol(callerIndex) )->getFirstJitTempIndex())))421{422if (comp->trace(OMR::inlining))423traceMsg(comp, "callSiteRemat: adding pending push #%d with store #%d to remat table\n",424storeTree->getNode()->getSymbolReference()->getReferenceNumber(),425node->getSymbolReference()->getReferenceNumber());426427comp->setOSRCallSiteRemat(comp->getCurrentInlinedSiteIndex(),428storeTree->getNode()->getSymbolReference(),429node->getSymbolReference());430}431}432}433}434}435436bool TR_InlinerBase::inlineCallTarget(TR_CallStack *callStack, TR_CallTarget *calltarget, bool inlinefromgraph, TR_PrexArgInfo *argInfo, TR::TreeTop** cursorTreeTop)437{438439TR_InlinerDelimiter delimiter(tracer(),"TR_InlinerBase::inlineCallTarget");440441char *sig = "multiLeafArrayCopy";442if (strncmp(calltarget->_calleeMethod->nameChars(), sig, strlen(sig)) == 0)443{444_nodeCountThreshold = 8192;445heuristicTrace(tracer(),"Setting _nodeCountThreshold to %d for multiLeafArrayCopy",_nodeCountThreshold);446}447448if (!((TR_J9InlinerPolicy* )getPolicy())->doCorrectnessAndSizeChecksForInlineCallTarget(callStack, calltarget, inlinefromgraph, argInfo))449{450//@TODO do we need to undo _nodeCountThreshold???!451return false;452}453454// Last chance to improve our prex info455//456if (!calltarget->_prexArgInfo)457calltarget->_prexArgInfo = getUtil()->computePrexInfo(calltarget);458459argInfo = TR_PrexArgInfo::enhance(calltarget->_prexArgInfo, argInfo, comp());460calltarget->_prexArgInfo = argInfo;461bool tracePrex = comp()->trace(OMR::inlining) || comp()->trace(OMR::invariantArgumentPreexistence);462if (tracePrex && argInfo)463{464traceMsg(comp(), "Final prex argInfo:\n");465argInfo->dumpTrace();466}467468if (!comp()->incInlineDepth(calltarget->_calleeSymbol,469calltarget->_myCallSite->_callNode,470!calltarget->_myCallSite->_isIndirectCall,471calltarget->_guard,472calltarget->_receiverClass,473argInfo))474{475return false;476}477478//OSR479int32_t numLivePendingPushSlots = 0;480int32_t nestingDepth = 0;481if (comp()->getOption(TR_EnableOSR))482{483computeNumLivePendingSlotsAndNestingDepth(_optimizer, calltarget, callStack, numLivePendingPushSlots, nestingDepth);484}485486// Add the pending pushes above this call to the OSRCallSiteRematTable487if (comp()->getOption(TR_EnableOSR)488&& !comp()->getOption(TR_DisableOSRCallSiteRemat)489&& comp()->getOSRMode() == TR::voluntaryOSR490&& comp()->isOSRTransitionTarget(TR::postExecutionOSR)491&& comp()->isPotentialOSRPointWithSupport(calltarget->_myCallSite->_callNodeTreeTop)492&& performTransformation(comp(), "O^O CALL SITE REMAT: populate OSR call site remat table for call [%p]\n", calltarget->_myCallSite->_callNode))493{494if (comp()->trace(OMR::inlining))495traceMsg(comp(), "callSiteRemat: populating OSR call site remat table for call [%p]\n", calltarget->_myCallSite->_callNode);496populateOSRCallSiteRematTable(_optimizer, calltarget, callStack);497}498499bool successful = inlineCallTarget2(callStack, calltarget, cursorTreeTop, inlinefromgraph, 99);500501// if inlining fails, we need to tell decInlineDepth to remove elements that502// we added during inlineCallTarget2503comp()->decInlineDepth(!successful);504505if (comp()->getOption(TR_EnableOSR))506{507comp()->incNumLivePendingPushSlots(-numLivePendingPushSlots);508comp()->incNumLoopNestingLevels(-nestingDepth);509}510511if (NumInlinedMethods != NULL)512{513NumInlinedMethods[comp()->getMethodHotness()]++;514InlinedSizes[comp()->getMethodHotness()] += TR::Compiler->mtd.bytecodeSize(calltarget->_calleeSymbol->getResolvedMethod()->getPersistentIdentifier());515}516return successful;517}518519TR_ResolvedMethod* TR_J9VirtualCallSite::findSingleJittedImplementer (TR_InlinerBase *inliner)520{521return comp()->getPersistentInfo()->getPersistentCHTable()->findSingleJittedImplementer(_receiverClass,TR::Compiler->cls.isInterfaceClass(comp(), _receiverClass) ? _cpIndex : _vftSlot,_callerResolvedMethod, comp(), _initialCalleeSymbol);522}523524bool TR_J9VirtualCallSite::findCallSiteForAbstractClass(TR_InlinerBase* inliner)525{526TR_PersistentCHTable *chTable = comp()->getPersistentInfo()->getPersistentCHTable();527TR_ResolvedMethod *implementer;528529bool canInline = (!comp()->compileRelocatableCode() || comp()->getOption(TR_UseSymbolValidationManager));530if (canInline && TR::Compiler->cls.isAbstractClass(comp(), _receiverClass) &&!comp()->getOption(TR_DisableAbstractInlining) &&531(implementer = chTable->findSingleAbstractImplementer(_receiverClass, _vftSlot, _callerResolvedMethod, comp())))532{533heuristicTrace(inliner->tracer(),"Found a single Abstract Implementer %p, signature = %s",implementer,inliner->tracer()->traceSignature(implementer));534TR_VirtualGuardSelection *guard = new (comp()->trHeapMemory()) TR_VirtualGuardSelection(TR_AbstractGuard, TR_MethodTest);535addTarget(comp()->trMemory(),inliner,guard,implementer,_receiverClass,heapAlloc);536return true;537}538539return false;540}541542TR_OpaqueClassBlock* TR_J9VirtualCallSite::getClassFromMethod ()543{544return _initialCalleeMethod->classOfMethod();545}546547// Ensure the call site is a basic invokevirtual; the bytecode is an 'invokevirtaul' and the548// cpIndex is the same as the call site _cpIndex. This will insure that the call site is not549// some type of transformed call site that may not be a valid case for allowing an isInstanceOf()550// call during AOT compiles551bool TR_J9VirtualCallSite::isBasicInvokeVirtual()552{553TR_OpaqueMethodBlock *method = ((TR_ResolvedJ9Method*)_initialCalleeMethod->owningMethod())->getPersistentIdentifier();554int32_t methodSize = TR::Compiler->mtd.bytecodeSize(method);555uintptr_t methodStart = TR::Compiler->mtd.bytecodeStart(method);556557TR_ASSERT_FATAL(_bcInfo.getByteCodeIndex() >= 0 && _bcInfo.getByteCodeIndex()+2 < methodSize, "Bytecode index can't be less than zero or higher than the methodSize");558559uint8_t *pc = (uint8_t *)(methodStart + _bcInfo.getByteCodeIndex());560TR_J9ByteCode bytecode = TR_J9ByteCodeIterator::convertOpCodeToByteCodeEnum(*pc);561//fprintf( stderr, "method %p, size %d, start %p, PC %p, BC: %d==%d? (%d)\n", method, methodSize, methodStart, pc, bytecode, J9BCinvokevirtual, (bytecode==J9BCinvokevirtual));562if (bytecode==J9BCinvokevirtual)563{564uint16_t cpIndex = *(uint16_t*)(pc + 1);565//fprintf( stderr, "BC cpIndex %d, callSite cpIndex %d\n", cpIndex, _cpIndex );566if (_cpIndex==cpIndex)567{568return true;569}570}571return false;572}573574bool TR_J9VirtualCallSite::findCallSiteTarget(TR_CallStack *callStack, TR_InlinerBase* inliner)575{576if (hasFixedTypeArgInfo())577{578bool result = findCallTargetUsingArgumentPreexistence(inliner);579if (!result) //findCallTargetUsingArgumentPreexistence couldn't reconcile class types580{581heuristicTrace(inliner->tracer(), "Don't inline anything at the risk of inlining dead code");582return false;583}584585if (numTargets()) //findCallTargetUsingArgumentPreexistence added a target586{587return true;588}589590//findCallTargetUsingArgumentPreexistence couldn't use argInfo591//Clear _ecsPrexArgInfo so it isn't propagated down to callees of this callsite592//And try other techniques593_ecsPrexArgInfo->set(0, NULL);594}595596tryToRefineReceiverClassBasedOnResolvedTypeArgInfo(inliner);597598// Refine receiver class based on CP class599// When we have an invokevirtual on an abstract method defined in an interface class,600// the call site's class will be more concrete than class of method.601// This happens when an abstract class implements an interface class without providing602// implementation for the given method, and the call site is refering to the method of603// the abstract class, the cp entry of the method ref will be resolved to j9method of604// the interface class. However, the class ref from cp will be resolved to the abstract605// class, which is more concrete606//607if (_cpIndex != -1 && _receiverClass && TR::Compiler->cls.isInterfaceClass(comp(), _receiverClass) && isBasicInvokeVirtual())608{609TR_ResolvedMethod* owningMethod = _initialCalleeMethod->owningMethod();610TR_ResolvedJ9Method* j9OwningMethod = (TR_ResolvedJ9Method*)owningMethod;611int32_t nameLen=0, sigLen=0;612char *cpMethodName = j9OwningMethod->getMethodNameFromConstantPool(_cpIndex, nameLen);613char *cpMethodSig = j9OwningMethod->getMethodSignatureFromConstantPool(_cpIndex, sigLen);614char *methodName = _initialCalleeMethod->nameChars();615char *methodSig = _initialCalleeMethod->signatureChars();616if (nameLen && nameLen == _initialCalleeMethod->nameLength() && sigLen && sigLen == _initialCalleeMethod->signatureLength() &&617strncmp(cpMethodName, methodName, nameLen)==0 && strncmp(cpMethodSig, methodSig, sigLen)==0)618{619int32_t classRefCPIndex = owningMethod->classCPIndexOfMethod(_cpIndex);620TR_OpaqueClassBlock* callSiteClass = owningMethod->getClassFromConstantPool(comp(), classRefCPIndex, true);621if (callSiteClass && callSiteClass != _receiverClass)622{623if (comp()->fej9()->isJavaLangObject(callSiteClass))624_isCallingObjectMethod = TR_yes;625else626{627TR_ASSERT_FATAL(fe()->isInstanceOf(callSiteClass, _receiverClass, true, true, true) == TR_yes , "CallSiteClass is incompatible with the receiverClass.");628_isCallingObjectMethod = TR_no;629if (comp()->trace(OMR::inlining))630{631char* oldClassSig = TR::Compiler->cls.classSignature(comp(), _receiverClass, comp()->trMemory());632char* callSiteClassSig = TR::Compiler->cls.classSignature(comp(), callSiteClass, comp()->trMemory());633traceMsg(comp(), "Receiver type %p sig %s is class of an interface method for invokevirtual, improve it to call site receiver type %p sig %s\n", _receiverClass, oldClassSig, callSiteClass, callSiteClassSig);634}635// Update receiver class636_receiverClass = callSiteClass;637}638}639}640}641642if (addTargetIfMethodIsNotOverriden(inliner) ||643addTargetIfMethodIsNotOverridenInReceiversHierarchy(inliner) ||644findCallSiteForAbstractClass(inliner) ||645addTargetIfThereIsSingleImplementer(inliner))646{647return true;648}649650return findProfiledCallTargets(callStack, inliner);651}652653/*654static TR_ResolvedMethod * findSingleImplementer(655TR_OpaqueClassBlock * thisClass, int32_t cpIndexOrVftSlot, TR_ResolvedMethod * callerMethod, TR::Compilation * comp, bool locked, TR_YesNoMaybe useGetResolvedInterfaceMethod)656{657if (comp->getOption(TR_DisableCHOpts))658return 0;659660661662TR_PersistentClassInfo * classInfo = comp->getPersistentInfo()->getPersistentCHTable()->findClassInfoAfterLocking(thisClass, comp, true);663if (!classInfo)664{665return 0;666}667668TR_ResolvedMethod *implArray[2]; // collect maximum 2 implementers if you can669int32_t implCount = TR_ClassQueries::collectImplementorsCapped(classInfo, implArray, 2, cpIndexOrVftSlot, callerMethod, comp, locked, useGetResolvedInterfaceMethod);670return (implCount == 1 ? implArray[0] : 0);671}672*/673674bool TR_J9InterfaceCallSite::findCallSiteTarget (TR_CallStack *callStack, TR_InlinerBase* inliner)675{676static char *minimizedInlineJIT = feGetEnv("TR_JITInlineMinimized");677678if (minimizedInlineJIT)679return false;680681if (hasFixedTypeArgInfo())682{683bool result = findCallTargetUsingArgumentPreexistence(inliner);684if (!result) //findCallTargetUsingArgumentPreexistence couldn't reconcile class types685{686heuristicTrace(inliner->tracer(), "Don't inline anything at the risk of inlining dead code");687return false;688}689690if (numTargets()) //findCallTargetUsingArgumentPreexistence added a target691{692return true;693}694695//findCallTargetUsingArgumentPreexistence couldn't use argInfo696//Clear _ecsPrexArgInfo so it wont be propagated down to callees of this callsite697//And try other techniques698_ecsPrexArgInfo->set(0, NULL);699}700701if (!_receiverClass)702{703int32_t len = _interfaceMethod->classNameLength();704char * s = TR::Compiler->cls.classNameToSignature(_interfaceMethod->classNameChars(), len, comp());705_receiverClass = comp()->fej9()->getClassFromSignature(s, len, _callerResolvedMethod, true);706}707708//TR_OpaqueClassBlock* _receiverClass = NULL;709tryToRefineReceiverClassBasedOnResolvedTypeArgInfo(inliner);710711//TR_ResolvedMethod* calleeResolvedMethod = inliner->findInterfaceImplementationToInline(_interfaceMethod, _cpIndex, _callerResolvedMethod, _receiverClass);712TR_ResolvedMethod* calleeResolvedMethod = comp()->getPersistentInfo()->getPersistentCHTable()->findSingleImplementer(_receiverClass, _cpIndex, _callerResolvedMethod, inliner->comp(), false, TR_yes);713714if (!comp()->performVirtualGuardNOPing() || (comp()->compileRelocatableCode() && !TR::Options::getCmdLineOptions()->allowRecompilation()))715{716calleeResolvedMethod = NULL;717}718719heuristicTrace(inliner->tracer(), "Found a Single Interface Implementer with Resolved Method %p for callsite %p",calleeResolvedMethod,this);720721if (calleeResolvedMethod && !calleeResolvedMethod->virtualMethodIsOverridden())722{723TR_VirtualGuardSelection * guard = new (comp()->trHeapMemory()) TR_VirtualGuardSelection(TR_InterfaceGuard, TR_MethodTest);724addTarget(comp()->trMemory(),inliner,guard,calleeResolvedMethod,_receiverClass,heapAlloc);725heuristicTrace(inliner->tracer(),"Call is an Interface with a Single Implementer guard %p\n", guard);726return true;727}728729return findProfiledCallTargets(callStack, inliner);730}731732TR_OpaqueClassBlock* TR_J9InterfaceCallSite::getClassFromMethod ()733{734int32_t len = _interfaceMethod->classNameLength();735char * s = TR::Compiler->cls.classNameToSignature(_interfaceMethod->classNameChars(), len, comp());736return comp()->fej9()->getClassFromSignature(s, len, _callerResolvedMethod, true);737}738739TR_ResolvedMethod* TR_J9InterfaceCallSite::getResolvedMethod (TR_OpaqueClassBlock* klass)740{741return _callerResolvedMethod->getResolvedInterfaceMethod(comp(), klass , _cpIndex);742}743744void TR_J9InterfaceCallSite::findSingleProfiledMethod(ListIterator<TR_ExtraAddressInfo>& sortedValuesIt, TR_AddressInfo * valueInfo, TR_InlinerBase* inliner)745{746return;747}748749bool TR_J9MethodHandleCallSite::findCallSiteTarget (TR_CallStack *callStack, TR_InlinerBase* inliner)750{751heuristicTrace(inliner->tracer(),"Call is MethodHandle thunk call.");752addTarget(comp()->trMemory(), inliner,753new (comp()->trHeapMemory()) TR_VirtualGuardSelection(TR_NoGuard),754_initialCalleeMethod,755_receiverClass, heapAlloc);756757return true;758}759760bool TR_J9MutableCallSite::findCallSiteTarget (TR_CallStack *callStack, TR_InlinerBase* inliner)761{762if (!_mcsReferenceLocation)763_mcsReferenceLocation = isMutableCallSiteTargetInvokeExact(this, inliner); // JSR292: Looking for calls through MutableCallSite764if (_mcsReferenceLocation)765{766// TODO:JSR292: This belongs behind the FE interface767heuristicTrace(inliner->tracer(),"Call is MutableCallSite.target.invokeExact call.");768if (!comp()->performVirtualGuardNOPing())769{770heuristicTrace(inliner->tracer()," Virtual guard NOPing disabled");771return false;772}773TR_VirtualGuardSelection *vgs = new (comp()->trHeapMemory()) TR_VirtualGuardSelection(TR_MutableCallSiteTargetGuard, TR_DummyTest);774vgs->_mutableCallSiteObject = _mcsReferenceLocation;775TR::KnownObjectTable *knot = comp()->getOrCreateKnownObjectTable();776777#if defined(J9VM_OPT_JITSERVER)778if (comp()->isOutOfProcessCompilation())779{780vgs->_mutableCallSiteEpoch = TR::KnownObjectTable::UNKNOWN;781bool knotEnabled = (knot != NULL);782auto stream = TR::CompilationInfo::getStream();783stream->write(JITServer::MessageType::KnownObjectTable_mutableCallSiteEpoch, _mcsReferenceLocation, knotEnabled);784785auto recv = stream->read<uintptr_t, TR::KnownObjectTable::Index, uintptr_t*>();786uintptr_t mcsObject = std::get<0>(recv);787TR::KnownObjectTable::Index knotIndex = std::get<1>(recv);788uintptr_t *objectPointerReference = std::get<2>(recv);789790if (mcsObject && knot && (knotIndex != TR::KnownObjectTable::UNKNOWN))791{792vgs->_mutableCallSiteEpoch = knotIndex;793knot->updateKnownObjectTableAtServer(knotIndex, objectPointerReference);794}795else796{797vgs->_mutableCallSiteObject = NULL;798}799}800else801#endif /* defined(J9VM_OPT_JITSERVER) */802{803TR::VMAccessCriticalSection mutableCallSiteEpoch(comp()->fej9());804vgs->_mutableCallSiteEpoch = TR::KnownObjectTable::UNKNOWN;805uintptr_t mcsObject = comp()->fej9()->getStaticReferenceFieldAtAddress((uintptr_t)_mcsReferenceLocation);806if (mcsObject && knot)807{808TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp()->fej9());809vgs->_mutableCallSiteEpoch = fej9->mutableCallSiteEpoch(comp(), mcsObject);810}811else812{813vgs->_mutableCallSiteObject = NULL;814}815}816817if (vgs->_mutableCallSiteEpoch != TR::KnownObjectTable::UNKNOWN)818{819#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)820TR::MethodSymbol::Kinds methodKind = TR::MethodSymbol::Static;821TR_OpaqueMethodBlock *targetJ9Method =822comp()->fej9()->targetMethodFromMethodHandle(comp(), vgs->_mutableCallSiteEpoch);823824TR_ASSERT_FATAL(825targetJ9Method != NULL,826"failed to find MCS target (obj%d) LambdaForm method",827(int)vgs->_mutableCallSiteEpoch);828829TR_ResolvedMethod *targetMethod = comp()->fej9()->createResolvedMethod(830comp()->trMemory(), targetJ9Method, callStack->_method);831832heuristicTrace(833inliner->tracer(),834"Refine callee of MCS target invokeBasic to %s\n",835targetMethod->signature(comp()->trMemory(), stackAlloc));836#else837TR::MethodSymbol::Kinds methodKind = TR::MethodSymbol::ComputedVirtual;838TR_ResolvedMethod *targetMethod = comp()->fej9()->createMethodHandleArchetypeSpecimen(839comp()->trMemory(),840knot->getPointerLocation(vgs->_mutableCallSiteEpoch),841_callerResolvedMethod);842#endif843TR_CallTarget *target = addTarget(comp()->trMemory(), inliner, vgs,844targetMethod, _receiverClass, heapAlloc);845TR_ASSERT(target , "There should be only one target for TR_MutableCallSite");846target->_calleeMethodKind = methodKind;847848heuristicTrace(849inliner->tracer(),850" addTarget: MutableCallSite %p epoch is obj%d",851vgs->_mutableCallSiteObject,852vgs->_mutableCallSiteEpoch);853854return true;855}856else if (vgs->_mutableCallSiteObject)857{858heuristicTrace(inliner->tracer()," MutableCallSite.epoch is currently NULL. Can't devirtualize.");859}860else861{862heuristicTrace(inliner->tracer()," MutableCallSite is NULL! That is rather unexpected.");863}864return false;865}866867return false;868}869870bool TR_InlinerBase::tryToGenerateILForMethod (TR::ResolvedMethodSymbol* calleeSymbol, TR::ResolvedMethodSymbol* callerSymbol, TR_CallTarget* calltarget)871{872TR_J9InlinerPolicy *j9inlinerPolicy = (TR_J9InlinerPolicy *) getPolicy();873return j9inlinerPolicy->_tryToGenerateILForMethod (calleeSymbol, callerSymbol, calltarget);874}875876void TR_InlinerBase::getBorderFrequencies(int32_t &hotBorderFrequency, int32_t &coldBorderFrequency, TR_ResolvedMethod * calleeResolvedMethod, TR::Node *callNode)877{878if (comp()->getMethodHotness() > warm)879{880hotBorderFrequency = comp()->isServerInlining() ? 2000 : 2500;881coldBorderFrequency = 0;882}883else if (!comp()->getOption(TR_DisableConservativeInlining) &&884calleeResolvedMethod->maxBytecodeIndex() >= comp()->getOptions()->getAlwaysWorthInliningThreshold() &&885!alwaysWorthInlining(calleeResolvedMethod, callNode))886{887hotBorderFrequency = 6000;888coldBorderFrequency = 1500;889}890else // old days891{892if (comp()->isServerInlining())893{894hotBorderFrequency = 2000;895coldBorderFrequency = 50;896}897else898{899hotBorderFrequency = 2500;900coldBorderFrequency = 1000;901}902}903904// Did the user specify specific values? If so, use those905if (comp()->getOptions()->getInlinerBorderFrequency() >= 0)906hotBorderFrequency = comp()->getOptions()->getInlinerBorderFrequency();907//if (comp()->getOptions()->getInlinerColdBorderFrequency() >= 0)908// coldBorderFrequency = comp()->getOptions()->getInlinerColdBorderFrequency();909if (comp()->getOptions()->getInlinerVeryColdBorderFrequency() >= 0)910coldBorderFrequency = comp()->getOptions()->getInlinerVeryColdBorderFrequency();911912913914return;915}916917918int TR_InlinerBase::checkInlineableWithoutInitialCalleeSymbol (TR_CallSite* callsite, TR::Compilation* comp)919{920if (!callsite->_isInterface)921{922return Unresolved_Callee;923}924925return InlineableTarget;926}927928929int32_t TR_InlinerBase::scaleSizeBasedOnBlockFrequency(int32_t bytecodeSize, int32_t frequency, int32_t borderFrequency, TR_ResolvedMethod * calleeResolvedMethod, TR::Node *callNode, int32_t coldBorderFrequency)930{931int32_t maxFrequency = MAX_BLOCK_COUNT + MAX_COLD_BLOCK_COUNT;932if (frequency > borderFrequency)933{934float factor = (float)(maxFrequency - frequency) / (float)maxFrequency;935factor = std::max(factor, 0.7f);936937938bytecodeSize = (int32_t)((float)bytecodeSize * factor);939if (bytecodeSize < 10) bytecodeSize = 10;940}941else if (frequency < coldBorderFrequency &&942!alwaysWorthInlining(calleeResolvedMethod, callNode))943{944945float factor = (float)frequency / (float)maxFrequency;946bytecodeSize = (int32_t)((float)bytecodeSize / (factor*factor));947}948949return bytecodeSize;950951}952953float TR_MultipleCallTargetInliner::getScalingFactor(float factor)954{955return std::max(factor, 0.7f);956}957958959void TR_ProfileableCallSite::findSingleProfiledReceiver(ListIterator<TR_ExtraAddressInfo>& sortedValuesIt, TR_AddressInfo * valueInfo, TR_InlinerBase* inliner)960{961962bool firstInstanceOfCheckFailed = false;963int32_t totalFrequency = valueInfo->getTotalFrequency();964965966for (TR_ExtraAddressInfo *profiledInfo = sortedValuesIt.getFirst(); profiledInfo != NULL; profiledInfo = sortedValuesIt.getNext())967{968int32_t freq = profiledInfo->_frequency;969TR_OpaqueClassBlock* tempreceiverClass = (TR_OpaqueClassBlock *) profiledInfo->_value;970971float val = (float)freq/(float)valueInfo->getTotalFrequency(); //x87 hardware rounds differently if you leave this division in compare972973974bool preferMethodTest = false;975976bool isClassObsolete = comp()->getPersistentInfo()->isObsoleteClass((void*)tempreceiverClass, comp()->fe());977978if (!isClassObsolete)979{980int32_t len = 1;981const char *className = TR::Compiler->cls.classNameChars(comp(), tempreceiverClass, len);982983if (!strncmp(className, "java/lang/ThreadLocal", 21) && !isInterface())984{985preferMethodTest = true;986}987// high opt level compiles during JIT STARTUP could be affected by classes being loaded - maximize the chances988// of success by using method tests989else if (comp()->getPersistentInfo()->getJitState() == STARTUP_STATE && comp()->getMethodHotness() >= hot)990{991preferMethodTest = true;992}993}994995996static const char* userMinProfiledCallFreq = feGetEnv("TR_MinProfiledCallFrequency");997static const float minProfiledCallFrequency = userMinProfiledCallFreq ? atof (userMinProfiledCallFreq) :998comp()->getOption(TR_DisableMultiTargetInlining) ? MIN_PROFILED_CALL_FREQUENCY : .10f;9991000if ((val >= minProfiledCallFrequency ||1001(firstInstanceOfCheckFailed && val >= SECOND_BEST_MIN_CALL_FREQUENCY)) &&1002!comp()->getPersistentInfo()->isObsoleteClass((void*)tempreceiverClass, comp()->fe()))1003{1004TR_OpaqueClassBlock* callSiteClass = _receiverClass ? _receiverClass : getClassFromMethod();10051006if (callSiteClass && !isInterface() && TR::Compiler->cls.isInterfaceClass(comp(), callSiteClass) && isCallingObjectMethod() != TR_yes)1007{1008// TR_J9VirtualCallSite::findCallSiteTarget() should have refined the _receiverClass, but it must have failed, we need to abort this inlining1009if (comp()->trace(OMR::inlining))1010traceMsg(comp(), "inliner: callSiteClass [%p] is an interface making it impossible to confirm correct context of the profiled class [%p]\n", callSiteClass, tempreceiverClass);1011callSiteClass = 0;1012}10131014bool profiledClassIsNotInstanceOfCallSiteClass = true;1015if (callSiteClass)1016{1017comp()->enterHeuristicRegion();1018profiledClassIsNotInstanceOfCallSiteClass = (fe()->isInstanceOf(tempreceiverClass, callSiteClass, true, true, true) != TR_yes);1019comp()->exitHeuristicRegion();1020}10211022if (profiledClassIsNotInstanceOfCallSiteClass)1023{1024inliner->tracer()->insertCounter(Not_Sane,_callNodeTreeTop);1025firstInstanceOfCheckFailed = true;10261027if (comp()->trace(OMR::inlining))1028traceMsg(comp(), "inliner: profiled class [%p] is not instanceof callSiteClass [%p]\n", tempreceiverClass, callSiteClass);10291030continue;1031}10321033comp()->enterHeuristicRegion();1034TR_ResolvedMethod* targetMethod = getResolvedMethod (tempreceiverClass);1035comp()->exitHeuristicRegion();10361037if (!targetMethod)1038{1039continue;1040}10411042//origMethod10431044TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp()->fe());1045// need to be able to store class chains for these methods1046if (comp()->compileRelocatableCode())1047{1048if (tempreceiverClass && comp()->getOption(TR_UseSymbolValidationManager))1049{1050if (!comp()->getSymbolValidationManager()->addProfiledClassRecord(tempreceiverClass))1051continue;1052/* call getResolvedMethod again to generate the validation records */1053TR_ResolvedMethod* target_method = getResolvedMethod (tempreceiverClass);10541055/* it is possible for getResolvedMethod to return NULL, since there might be1056* a problem when generating validation records1057*/1058if (!target_method)1059continue;10601061TR_OpaqueClassBlock *classOfMethod = target_method->classOfMethod();1062SVM_ASSERT_ALREADY_VALIDATED(comp()->getSymbolValidationManager(), classOfMethod);1063}10641065if (!fej9->canRememberClass(tempreceiverClass) ||1066!fej9->canRememberClass(callSiteClass))1067{1068if (comp()->trace(OMR::inlining))1069traceMsg(comp(), "inliner: profiled class [%p] or callSiteClass [%p] cannot be rememberd in shared cache\n", tempreceiverClass, callSiteClass);1070continue;1071}1072}10731074TR_VirtualGuardSelection *guard = NULL;1075if (preferMethodTest)1076guard = new (comp()->trHeapMemory()) TR_VirtualGuardSelection(TR_ProfiledGuard, TR_MethodTest, tempreceiverClass);1077else1078guard = new (comp()->trHeapMemory()) TR_VirtualGuardSelection(TR_ProfiledGuard, TR_VftTest, tempreceiverClass);10791080// if the previous value was from the interpreter profiler1081// don't apply the optimization1082TR_ByteCodeInfo &bcInfo = _bcInfo; //callNode->getByteCodeInfo();1083if (valueInfo->getTopProbability() == 1.0f && valueInfo->getProfiler()->getSource() < LastProfiler)1084guard->setIsHighProbablityProfiledGuard();10851086heuristicTrace(inliner->tracer(),"Creating a profiled call. callee Symbol %p frequencyadjustment %f",_initialCalleeSymbol, val);1087addTarget(comp()->trMemory(),inliner,guard,targetMethod,tempreceiverClass,heapAlloc,val);10881089if (comp()->getOption(TR_DisableMultiTargetInlining))1090return;1091}1092else // if we're below the above threshold, lets stop considering call targets1093{1094if (comp()->trace(OMR::inlining))1095traceMsg(comp(), "bailing, below inlining threshold\n");1096break;1097}10981099}11001101}110211031104void TR_ProfileableCallSite::findSingleProfiledMethod(ListIterator<TR_ExtraAddressInfo>& sortedValuesIt, TR_AddressInfo * valueInfo, TR_InlinerBase* inliner)1105{1106if (!comp()->cg()->getSupportsProfiledInlining())1107{1108return;1109}11101111uint32_t totalFrequency = valueInfo->getTotalFrequency();11121113if (totalFrequency<=0)1114{1115return;1116}1117TR_OpaqueClassBlock* callSiteClass = _receiverClass ? _receiverClass : getClassFromMethod();1118TR_ASSERT_FATAL(!isInterface(), "Interface call site called TR_ProfileableCallSite::findSingleProfiledMethod()");1119if (!callSiteClass || (TR::Compiler->cls.isInterfaceClass(comp(), callSiteClass) && isCallingObjectMethod() != TR_yes))1120{1121// TR_J9VirtualCallSite::findCallSiteTarget() should refine the _receiverClass, but if it failed, we need to abort this inlining1122if (callSiteClass && comp()->trace(OMR::inlining))1123traceMsg(comp(), "callSiteClass [%p] is an interface making it impossible to confirm correct context for any profiled class\n", callSiteClass);1124return;1125}11261127// first let's do sanity test on all profiled targets1128if (comp()->trace(OMR::inlining))1129traceMsg(comp(), "No decisive class profiling info for the virtual method, we'll try to see if more than one class uses the same method implementation.\n");11301131bool classValuesAreSane = true;1132for (TR_ExtraAddressInfo *profiledInfo = sortedValuesIt.getFirst(); profiledInfo != NULL; profiledInfo = sortedValuesIt.getNext())1133{1134TR_OpaqueClassBlock *clazz = (TR_OpaqueClassBlock *) profiledInfo->_value;1135bool isClassObsolete = comp()->getPersistentInfo()->isObsoleteClass((void*)clazz, comp()->fe());1136if (isClassObsolete)1137{1138classValuesAreSane = false;1139break;1140}11411142TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp()->fe());1143// need to be able to store class chains for these methods1144if (comp()->compileRelocatableCode())1145{1146if (clazz && comp()->getOption(TR_UseSymbolValidationManager))1147if (!comp()->getSymbolValidationManager()->addProfiledClassRecord(clazz))1148{1149classValuesAreSane = false;1150break;1151}11521153if (!fej9->canRememberClass(clazz) ||1154!fej9->canRememberClass(callSiteClass))1155{1156classValuesAreSane = false;1157break;1158}1159}1160}11611162if (!classValuesAreSane)1163return;11641165if (comp()->trace(OMR::inlining))1166traceMsg(comp(), "OK, all classes check out, we'll try to get their method implementations.\n");11671168TR_ScratchList<TR_AddressInfo::ProfiledMethod> methodsList(comp()->trMemory());1169// this API doesn't do a sort1170valueInfo->getMethodsList(comp(), _callerResolvedMethod, callSiteClass, _vftSlot, &methodsList);11711172int numMethods = methodsList.getSize();11731174if (comp()->trace(OMR::inlining))1175traceMsg(comp(), "OK, all classes check out, we'll try to get their method implementations (%d).\n", numMethods);117611771178ListIterator<TR_AddressInfo::ProfiledMethod> methodValuesIt(&methodsList);1179TR_AddressInfo::ProfiledMethod *profiledMethodInfo;1180TR_AddressInfo::ProfiledMethod *bestMethodInfo = methodValuesIt.getFirst();11811182float methodProbability = .0f;11831184if (bestMethodInfo)1185{1186for (profiledMethodInfo = methodValuesIt.getNext(); profiledMethodInfo != NULL; profiledMethodInfo = methodValuesIt.getNext())1187{1188if (profiledMethodInfo->_frequency > bestMethodInfo->_frequency)1189bestMethodInfo = profiledMethodInfo;1190}11911192methodProbability = (float)bestMethodInfo->_frequency/(float)totalFrequency;11931194if (comp()->trace(OMR::inlining))1195{1196TR_ResolvedMethod *targetMethod = (TR_ResolvedMethod *)bestMethodInfo->_value;1197traceMsg(comp(), "Found a target method %s with probability of %f%%.\n",1198targetMethod->signature(comp()->trMemory()), methodProbability * 100.0);1199}12001201static const char* userMinProfiledCallFreq = feGetEnv("TR_MinProfiledCallFrequency");1202static const float minProfiledCallFrequency = userMinProfiledCallFreq ? atof (userMinProfiledCallFreq) : MIN_PROFILED_CALL_FREQUENCY;12031204if (methodProbability >= minProfiledCallFrequency)1205{1206TR_ResolvedMethod *targetMethod = (TR_ResolvedMethod *)bestMethodInfo->_value;1207TR_OpaqueClassBlock *targetClass = targetMethod->classOfMethod();12081209if (targetMethod && targetClass)1210{1211TR_VirtualGuardSelection *guard = new (comp()->trHeapMemory()) TR_VirtualGuardSelection(TR_ProfiledGuard, TR_MethodTest, targetClass);1212addTarget(comp()->trMemory(), inliner, guard, targetMethod, targetClass, heapAlloc, methodProbability);1213if (comp()->trace(OMR::inlining))1214{1215TR_ResolvedMethod *targetMethod = (TR_ResolvedMethod *)bestMethodInfo->_value;1216traceMsg(comp(), "Added target method %s with probability of %f%%.\n",1217targetMethod->signature(comp()->trMemory()), methodProbability * 100.0);1218char* sig = TR::Compiler->cls.classSignature(comp(), targetClass, comp()->trMemory());1219traceMsg(comp(), "target class %s\n", sig);1220}1221return;1222}1223}1224}1225else if (comp()->trace(OMR::inlining))1226traceMsg(comp(), "Failed to find any methods compatible with callsite class %p signature %s\n", callSiteClass, TR::Compiler->cls.classSignature(comp(), callSiteClass, comp()->trMemory()));1227}12281229bool TR_ProfileableCallSite::findProfiledCallTargets (TR_CallStack *callStack, TR_InlinerBase* inliner)1230{1231heuristicTrace(inliner->tracer(),"Looking for a profiled Target %p \n", this);1232TR_ValueProfileInfoManager * profileManager = TR_ValueProfileInfoManager::get(comp());12331234if (!profileManager)1235{1236heuristicTrace(inliner->tracer()," no profileManager %p\n", this);1237return false;1238}12391240TR_AddressInfo *valueInfo = static_cast<TR_AddressInfo*>(profileManager->getValueInfo(_bcInfo, comp(), AddressInfo));12411242if(!valueInfo || comp()->getOption(TR_DisableProfiledInlining))1243{1244heuristicTrace(inliner->tracer()," no valueInfo or valueInfo is not of AddressInfo type or TR_DisableProfiledInlining specified for %p\n", this);1245return false;1246}1247124812491250TR_ScratchList<TR_ExtraAddressInfo> valuesSortedByFrequency(comp()->trMemory());1251valueInfo->getSortedList(comp(), &valuesSortedByFrequency);1252ListIterator<TR_ExtraAddressInfo> sortedValuesIt(&valuesSortedByFrequency);12531254uint32_t totalFrequency = valueInfo->getTotalFrequency();1255((TR_J9InlinerTracer *)inliner->tracer())->dumpProfiledClasses(sortedValuesIt, totalFrequency);12561257//@TODO: put in a separate function1258if (inliner->isEDODisableInlinedProfilingInfo() && _callerResolvedMethod != comp()->getCurrentMethod())1259{1260// if the previous value was from the interpreter profiler1261// don't devirtualize1262if (valueInfo->getProfiler()->getSource() == LastProfiler)1263{1264inliner->tracer()->insertCounter(EDO_Callee,_callNodeTreeTop);1265heuristicTrace(inliner->tracer()," EDO callsite %p, so not inlineable\n", this);1266return false;1267}1268}12691270findSingleProfiledReceiver(sortedValuesIt, valueInfo, inliner);1271if (!numTargets())1272{1273findSingleProfiledMethod(sortedValuesIt, valueInfo, inliner);1274}12751276return numTargets();1277}12781279128012811282