Path: blob/master/runtime/compiler/optimizer/J9Inliner.hpp
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#ifndef INLINERTEMPFORJ9_INCL23#define INLINERTEMPFORJ9_INCL2425#include "j9cfg.h"26#include "ras/LogTracer.hpp"27#include "runtime/J9ValueProfiler.hpp"2829class OMR_InlinerPolicy;30class OMR_InlinerUtil;31class TR_InlinerBase;32class TR_J9InnerPreexistenceInfo;333435/**36* Class TR_MultipleCallTargetInliner37* ==================================38*39* Exception Directed Optimization (EDO) enables more aggressive40* inlining that the JIT does in cases when the call graph of the41* callee being inlined has some throw statements that would get42* caught in a catch block of the caller.43*44* The end goal is to give the JIT optimizer (value propagation in45* particular) the opportunity to convert a throw statement into a goto46* statement in cases when it can be proven at compile time that the throw47* would be caught by a specific catch block in the same compiled method.48*49* The advantage of this optimization is being able to avoid the throw/catch50* flow of control that typically is implemented by some form of stack51* walking in the JVM; stack walking can be quite an expensive operation52* especially when compared with other simpler ways of transferring53* flow of control, like a goto for example.54*55* Value propagation propagates type information as part of the analysis56* and this means that it can determine if the exception thrown can in fact57* be caught by a particular catch block or not based on the type of the58* exception and the types that the catch block handles according to the59* exception table information in the bytecodes.60*61* EDO depends on profiling throw statements and catch blocks, and62* determining those operations that are frequently executed and then63* attempting to bring the frequently executed throw and catch together64* into the same compilation unit (method) by inlining aggressively.65*/6667class TR_MultipleCallTargetInliner : public TR_InlinerBase68{69public:7071template <typename FunctObj>72void recursivelyWalkCallTargetAndPerformAction(TR_CallTarget *ct, FunctObj &action);7374//void generateNodeEstimate(TR_CallTarget *ct, TR::Compilation *comp);7576class generateNodeEstimate77{78public:79generateNodeEstimate() : _nodeEstimate(0){ }80void operator()(TR_CallTarget *ct, TR::Compilation *comp);81int32_t getNodeEstimate() { return _nodeEstimate; }82private:83int32_t _nodeEstimate;84};8586TR_MultipleCallTargetInliner(TR::Optimizer *, TR::Optimization *);8788virtual bool inlineCallTargets(TR::ResolvedMethodSymbol *, TR_CallStack *, TR_InnerPreexistenceInfo *);89virtual bool exceedsSizeThreshold(TR_CallSite *callSite, int bytecodeSize, TR::Block * callNodeBlock, TR_ByteCodeInfo & bcInfo, int32_t numLocals=0, TR_ResolvedMethod * caller = 0, TR_ResolvedMethod * calleeResolvedMethod = 0, TR::Node * callNode = 0, bool allConsts = false);9091TR_LinkHead<TR_CallTarget> _callTargets; // This list only contains the call targets from top most level9293protected:94virtual int32_t scaleSizeBasedOnBlockFrequency(int32_t bytecodeSize, int32_t frequency, int32_t borderFrequency, TR_ResolvedMethod * calleeResolvedMethod, TR::Node *callNode, int32_t coldBorderFrequency = 0);95float getScalingFactor(float factor);96virtual bool supportsMultipleTargetInlining () { return true ; }9798void walkCallSites(TR::ResolvedMethodSymbol *, TR_CallStack *, TR_InnerPreexistenceInfo *, int32_t walkDepth);99void walkCallSite( TR::ResolvedMethodSymbol * calleeSymbol, TR_CallStack * callStack,100TR::TreeTop * callNodeTreeTop, TR::Node * parent, TR::Node * callNode, TR_VirtualGuardSelection *guard,101TR_OpaqueClassBlock * thisClass, bool inlineNonRecursively, int32_t walkDepth);102private:103bool analyzeCallSite(TR::ResolvedMethodSymbol *, TR_CallStack *, TR::TreeTop *, TR::Node *, TR::Node *);104void weighCallSite( TR_CallStack * callStack , TR_CallSite *callsite, bool currentBlockHasExceptionSuccessors,bool dontAddCalls=false);105106int32_t applyArgumentHeuristics(TR_LinkHead<TR_ParameterMapping> &map, int32_t originalWeight, TR_CallTarget *target);107bool eliminateTailRecursion(TR::ResolvedMethodSymbol *, TR_CallStack *, TR::TreeTop *, TR::Node *, TR::Node *, TR_VirtualGuardSelection *);108void assignArgumentsToParameters(TR::ResolvedMethodSymbol *, TR::TreeTop *, TR::Node *);109bool isLargeCompiledMethod(TR_ResolvedMethod *calleeResolvedMethod, int32_t bytecodeSize, int32_t freq);110/* \brief111* This API processes the call targets got chopped off from \ref _calltargets112*113* \parm firstChoppedOffcalltarget114* the start of the targets that should be chopped off from \ref _callTargets115*116* \parm lastTargetToInline117* the tail of _callTargets118*119* \notes120* Call targets are chopped off from \ref _callTargets list because of global budget limit like node counts and total weight.121* This function chooses to keep some chopped of targets if they meet certain conditions.122*/123void processChoppedOffCallTargets(TR_CallTarget* lastTargetToInline, TR_CallTarget *firstChoppedOffcalltarget, int estimateAndRefineBytecodeSize);124125/*126* \brief127* Recursively walk through the sub call graph of a given calltarget and clean up all targets128* from their respective callsites if chopped of from _callTargets129*130* \return131* True if the given calltarget should be inlined132*/133bool inlineSubCallGraph(TR_CallTarget* calltarget);134};135136class TR_J9InlinerUtil: public OMR_InlinerUtil137{138friend class TR_InlinerBase;139friend class TR_MultipleCallTargetInliner;140public:141TR_J9InlinerUtil(TR::Compilation *comp);142virtual void adjustByteCodeSize(TR_ResolvedMethod *calleeResolvedMethod, bool isInLoop, TR::Block *block, int &bytecodeSize);143virtual void adjustCallerWeightLimit(TR::ResolvedMethodSymbol *callSymbol, int &callerWeightLimit);144virtual void adjustMethodByteCodeSizeThreshold(TR::ResolvedMethodSymbol *callSymbol, int &methodByteCodeSizeThreshold);145virtual bool addTargetIfMethodIsNotOverridenInReceiversHierarchy(TR_IndirectCallSite *callsite);146virtual bool addTargetIfThereIsSingleImplementer (TR_IndirectCallSite *callsite);147virtual TR_ResolvedMethod *findSingleJittedImplementer(TR_IndirectCallSite *callsite);148virtual TR_PrexArgInfo* createPrexArgInfoForCallTarget(TR_VirtualGuardSelection *guard, TR_ResolvedMethod *implementer);149virtual TR_InlinerTracer * getInlinerTracer(TR::Optimization *optimization);150virtual TR_PrexArgInfo *computePrexInfo(TR_CallTarget *target);151virtual TR_PrexArgInfo *computePrexInfo(TR_CallTarget *target, TR_PrexArgInfo *callerArgInfo);152static TR_PrexArgInfo *computePrexInfo(TR_InlinerBase *inliner, TR_CallSite *site, TR_PrexArgInfo *callerArgInfo = NULL);153virtual void refineInlineGuard(TR::Node *callNode, TR::Block *&block1, TR::Block *&block2,154bool &appendTestToBlock1, TR::ResolvedMethodSymbol * callerSymbol, TR::TreeTop *cursorTree,155TR::TreeTop *&virtualGuard, TR::Block *block4);156virtual void 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);157static void checkForConstClass(TR_CallTarget *target, TR_LogTracer *tracer);158virtual bool needTargetedInlining(TR::ResolvedMethodSymbol *callee);159virtual void requestAdditionalOptimizations(TR_CallTarget *calltarget);160protected:161virtual void refineColdness (TR::Node* node, bool& isCold);162virtual void computeMethodBranchProfileInfo (TR::Block * cfgBlock, TR_CallTarget* calltarget, TR::ResolvedMethodSymbol* callerSymbol);163virtual int32_t getCallCount(TR::Node *callNode);164virtual TR_InnerPreexistenceInfo *createInnerPrexInfo(TR::Compilation * c, TR::ResolvedMethodSymbol *methodSymbol, TR_CallStack *callStack, TR::TreeTop *callTree, TR::Node *callNode, TR_VirtualGuardKind guardKind);165virtual void estimateAndRefineBytecodeSize(TR_CallSite* callsite, TR_CallTarget* target, TR_CallStack *callStack, int32_t &bytecodeSize);166virtual TR_TransformInlinedFunction *getTransformInlinedFunction(TR::ResolvedMethodSymbol *, TR::ResolvedMethodSymbol *, TR::Block *, TR::TreeTop *,167TR::Node *, TR_ParameterToArgumentMapper &, TR_VirtualGuardSelection *, List<TR::SymbolReference> &,168List<TR::SymbolReference> &, List<TR::SymbolReference> &);169};170171class TR_J9InlinerPolicy : public OMR_InlinerPolicy172{173friend class TR_J9InlinerUtil;174friend class TR_InlinerBase;175friend class TR_MultipleCallTargetInliner;176public:177TR_J9InlinerPolicy(TR::Compilation *comp);178virtual bool inlineRecognizedMethod(TR::RecognizedMethod method);179virtual bool tryToInlineTrivialMethod (TR_CallStack* callStack, TR_CallTarget* calltarget);180bool isInlineableJNI(TR_ResolvedMethod *method,TR::Node *callNode);181virtual bool alwaysWorthInlining(TR_ResolvedMethod * calleeMethod, TR::Node *callNode);182bool adjustFanInSizeInExceedsSizeThreshold(int bytecodeSize,183uint32_t& calculatedSize,184TR_ResolvedMethod* callee,185TR_ResolvedMethod* caller,186int32_t bcIndex);187void adjustFanInSizeInWeighCallSite(int32_t& weight,188int32_t size,189TR_ResolvedMethod* callee,190TR_ResolvedMethod* caller,191int32_t bcIndex);192virtual bool aggressivelyInlineInLoops();193virtual void determineInliningHeuristic(TR::ResolvedMethodSymbol *callerSymbol);194virtual void determineAggressionInLoops(TR::ResolvedMethodSymbol *callerSymbol);195virtual int32_t getInitialBytecodeSize(TR_ResolvedMethod *feMethod, TR::ResolvedMethodSymbol * methodSymbol, TR::Compilation *comp);196virtual bool tryToInline(TR_CallTarget *, TR_CallStack *, bool);197virtual bool inlineMethodEvenForColdBlocks(TR_ResolvedMethod *method);198virtual bool willBeInlinedInCodeGen(TR::RecognizedMethod method);199virtual bool canInlineMethodWhileInstrumenting(TR_ResolvedMethod *method);200virtual bool shouldRemoveDifferingTargets(TR::Node *callNode);201virtual bool skipHCRGuardForCallee(TR_ResolvedMethod* callee);202virtual bool dontPrivatizeArgumentsForRecognizedMethod(TR::RecognizedMethod recognizedMethod);203virtual bool replaceSoftwareCheckWithHardwareCheck(TR_ResolvedMethod *calleeMethod);204virtual bool suitableForRemat(TR::Compilation *comp, TR::Node *callNode, TR_VirtualGuardSelection *guard);205206#ifdef J9VM_OPT_JAVA_CRYPTO_ACCELERATION207virtual bool willInlineCryptoMethodInCodeGen(TR::RecognizedMethod method);208#endif209210protected:211bool _aggressivelyInlineInLoops;212void createTempsForUnsafeCall( TR::TreeTop *callNodeTreeTop, TR::Node * unsafeCallNode );213TR::Node * inlineGetClassAccessFlags(TR::ResolvedMethodSymbol *, TR::ResolvedMethodSymbol *, TR::TreeTop *, TR::Node *);214bool inlineUnsafeCall(TR::ResolvedMethodSymbol *, TR::ResolvedMethodSymbol *, TR::TreeTop *, TR::Node *);215TR::Block * addNullCheckForUnsafeGetPut(TR::Node* unsafeAddress, TR::SymbolReference* newSymbolReferenceForAddress, TR::TreeTop* callNodeTreeTop, TR::TreeTop* directAccessTreeTop, TR::TreeTop* arrayDirectAccessTreeTop, TR::TreeTop* indirectAccessTreeTop);216bool createUnsafePutWithOffset(TR::ResolvedMethodSymbol *, TR::ResolvedMethodSymbol *, TR::TreeTop *, TR::Node *, TR::DataType, bool, bool needNullCheck = false, bool isOrdered = false);217TR::TreeTop* genDirectAccessCodeForUnsafeGetPut(TR::Node* callNode, bool conversionNeeded, bool isUnsafeGet);218void createTempsForUnsafePutGet(TR::Node*& unsafeAddress, TR::Node* unsafeCall, TR::TreeTop* callNodeTreeTop, TR::Node*& offset, TR::SymbolReference*& newSymbolReferenceForAddress, bool isUnsafeGet);219bool createUnsafeGet(TR::ResolvedMethodSymbol *, TR::ResolvedMethodSymbol *, TR::TreeTop *, TR::Node *, TR::DataType, bool compress = true);220bool createUnsafePut(TR::ResolvedMethodSymbol *, TR::ResolvedMethodSymbol *, TR::TreeTop *, TR::Node *, TR::DataType, bool compress = true);221TR::Node * createUnsafeAddress(TR::Node *);222bool createUnsafeGetWithOffset(TR::ResolvedMethodSymbol *, TR::ResolvedMethodSymbol *, TR::TreeTop *, TR::Node *, TR::DataType, bool, bool needNullCheck = false);223TR::Node * createUnsafeAddressWithOffset(TR::Node *);224bool createUnsafeFence(TR::TreeTop *, TR::Node *, TR::ILOpCodes);225226TR::Node * createUnsafeMonitorOp(TR::ResolvedMethodSymbol *calleeSymbol, TR::ResolvedMethodSymbol *callerSymbol, TR::TreeTop * callNodeTreeTop, TR::Node * unsafeCall, bool isEnter);227bool createUnsafeCASCallDiamond(TR::TreeTop *, TR::Node *);228TR::TreeTop* genClassCheckForUnsafeGetPut(TR::Node* offset);229TR::TreeTop* genClassCheckForUnsafeGetPut(TR::Node* offset, bool isNotLowTagged);230231/** \brief232* Generates the indirect access for an unsafe get/put operation given a direct access. This function will233* replicate the entire direct access tree passed in (see \p directAccessOrTempStoreNode) and update the234* symbol reference of the unsafe get/put operation to represent an indirect access.235*236* \param directAccessOrTempStoreNode237* The direct access of the unsafe operation or a temp store of the direct access.238*239* \param unsafeAddress240* The unsafe address to access.241*242* \return243* The tree top representing the indirect access along with the potential temp store in case of a get244* operation.245*/246TR::TreeTop* genIndirectAccessCodeForUnsafeGetPut(TR::Node* directAccessOrTempStoreNode, TR::Node* unsafeAddress);247248void createAnchorNodesForUnsafeGetPut(TR::TreeTop* treeTop, TR::DataType type, bool isUnsafeGet);249TR::Node * genCompressedRefs(TR::Node *, bool genTT = true, int32_t isLoad = 1);250void genCodeForUnsafeGetPut(TR::Node* unsafeAddress, TR::TreeTop* callNodeTreeTop, TR::TreeTop* prevTreeTop, TR::SymbolReference* newSymbolReferenceForAddress, TR::TreeTop* directAccessTreeTop, TR::TreeTop* lowTagCmpTree, bool needNullCheck, bool isUnsafeGet, bool conversionNeeded, TR::Block * joinBlock, TR_OpaqueClassBlock *javaLangClass, TR::Node* orderedCallNode);251virtual bool callMustBeInlined(TR_CallTarget *calltarget);252bool mustBeInlinedEvenInDebug(TR_ResolvedMethod * calleeMethod, TR::TreeTop *callNodeTreeTop);253bool _tryToGenerateILForMethod (TR::ResolvedMethodSymbol* calleeSymbol, TR::ResolvedMethodSymbol* callerSymbol, TR_CallTarget* calltarget);254bool doCorrectnessAndSizeChecksForInlineCallTarget(TR_CallStack *callStack, TR_CallTarget *calltarget, bool inlinefromgraph, TR_PrexArgInfo *argInfo);255bool validateArguments(TR_CallTarget *calltarget, TR_LinkHead<TR_ParameterMapping> &map);256virtual bool supressInliningRecognizedInitialCallee(TR_CallSite* callsite, TR::Compilation* comp);257virtual TR_InlinerFailureReason checkIfTargetInlineable(TR_CallTarget* target, TR_CallSite* callsite, TR::Compilation* comp);258/** \brief259* This query decides whether the given method is JSR292 related260*/261static bool isJSR292Method(TR_ResolvedMethod *resolvedMethod);262/** \brief263* This query decides whether the given JSR292 callee is worthing inlining264*265* \notes266* The methods are in 3 kinds: 1. VarHandle operation methods 2. small getters 3. method handle thunk267*/268static bool isJSR292AlwaysWorthInlining(TR_ResolvedMethod *resolvedMethod);269/** \brief270* This query defines a group of methods that are small getters in the java/lang/invoke package271*/272static bool isJSR292SmallGetterMethod(TR_ResolvedMethod *resolvedMethod);273/** \brief274* This query defines a group of methods that are small helpers in the java/lang/invoke package275*/276static bool isJSR292SmallHelperMethod(TR_ResolvedMethod *resolvedMethod);277};278279class TR_J9JSR292InlinerPolicy : public TR_J9InlinerPolicy280{281friend class TR_J9InlinerUtil;282friend class TR_InlinerBase;283friend class TR_MultipleCallTargetInliner;284public:285TR_J9JSR292InlinerPolicy(TR::Compilation *comp);286protected:287virtual TR_InlinerFailureReason checkIfTargetInlineable(TR_CallTarget* target, TR_CallSite* callsite, TR::Compilation* comp);288};289290class TR_J9TransformInlinedFunction : public TR_TransformInlinedFunction291{292public:293TR_J9TransformInlinedFunction(294TR::Compilation *c, TR_InlinerTracer *tracer,TR::ResolvedMethodSymbol * callerSymbol, TR::ResolvedMethodSymbol * calleeSymbol,295TR::Block * callNodeBlock, TR::TreeTop * callNodeTreeTop, TR::Node * callNode,296TR_ParameterToArgumentMapper & mapper, TR_VirtualGuardSelection *guard,297List<TR::SymbolReference> & temps, List<TR::SymbolReference> & availableTemps,298List<TR::SymbolReference> & availableTemps2);299virtual void transform();300private:301void transformSynchronizedMethod(TR_ResolvedMethod *);302TR::Block * appendCatchBlockForInlinedSyncMethod(TR_ResolvedMethod *, TR::TreeTop * , int32_t, int32_t, bool addBlocks = true);303bool isSyncReturnBlock(TR::Compilation *comp, TR::Block * b);304// { RTSJ Support begins305void wrapCalleeInTryRegion(bool, bool, TR_ResolvedMethod *);306TR::TreeTop * createThrowCatchBlock(bool, bool, TR::CFG *, TR::Block *, TR::TreeTop *, TR::SymbolReference *, int32_t, TR_ScratchList<TR::Block> & newCatchBlocks);307TR::Block * appendCatchBlockToRethrowException(TR_ResolvedMethod *, TR::TreeTop *, bool, int32_t, int32_t, bool addBlocks = true);308// } RTSJ Support ends309};310311class TR_J9InnerPreexistenceInfo : public TR_InnerPreexistenceInfo312{313public:314TR_J9InnerPreexistenceInfo(TR::Compilation * c, TR::ResolvedMethodSymbol *methodSymbol, TR_CallStack *callStack,315TR::TreeTop *callTree, TR::Node *callNode,316TR_VirtualGuardKind _guardKind);317virtual bool perform(TR::Compilation *comp, TR::Node *guardNode, bool & disableTailRecursion);318class ParmInfo319{320public:321TR_ALLOC(TR_Memory::Inliner);322ParmInfo(TR::ParameterSymbol *innerParm, TR::ParameterSymbol *outerParm = 0);323324void setOuterSymbol(TR::ParameterSymbol *outerParm) { _outerParm = outerParm; }325void setNotInvariant() { _isInvariant = false; }326bool isInvariant() { return _isInvariant; }327328TR::ParameterSymbol *_outerParm; // may be null329TR::ParameterSymbol *_innerParm; // never null330bool _isInvariant;331};332333struct PreexistencePoint334{335TR_ALLOC(TR_Memory::Inliner);336PreexistencePoint(TR_CallStack *callStack, int32_t ordinal) :337_callStack(callStack), _ordinal(ordinal) {}338339TR_CallStack *_callStack;340int32_t _ordinal;341};342343ParmInfo *getParmInfo(int32_t ordinal) { return _parameters[ordinal]; }344PreexistencePoint *getPreexistencePoint(int32_t ordinal);345void addInnerAssumption(TR_InnerAssumption *a) { _assumptions.add(a); }346List<TR_InnerAssumption> &getInnerAssumptions() { return _assumptions; }347private:348PreexistencePoint *getPreexistencePointImpl(int32_t ordinal, TR_CallStack *prevCallStack);349ParmInfo **_parameters; // information about the address type parameters350};351352class TR_J9InlinerTracer : public TR_InlinerTracer353{354public:355TR_J9InlinerTracer(TR::Compilation *comp, TR_FrontEnd *fe, TR::Optimization *opt);356void dumpProfiledClasses (ListIterator<TR_ExtraAddressInfo>& sortedValuesIt, uint32_t totalFrequency = 1);357};358#endif359360361