diff --git a/compiler/optimizer/Inliner.cpp b/compiler/optimizer/Inliner.cpp index e69e1af06fa..726954ee7ee 100644 --- a/compiler/optimizer/Inliner.cpp +++ b/compiler/optimizer/Inliner.cpp @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corp. and others + * Copyright (c) 2000, 2021 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -1146,7 +1146,8 @@ TR_InlineCall::inlineCall(TR::TreeTop * callNodeTreeTop, TR_OpaqueClassBlock * t if (comp()->trace(OMR::inlining)) traceMsg(comp(), "inliner: Setting current inline depth=%d\n", currentInlineDepth); - calltarget->_prexArgInfo = new (trHeapMemory()) TR_PrexArgInfo(calltarget->_myCallSite->_callNode->getNumArguments(), trMemory()); + TR_PrexArgInfo *callerArgInfo = comp()->getCurrentInlinedCallArgInfo(); + calltarget->_prexArgInfo = getUtil()->computePrexInfo(calltarget, callerArgInfo); // this is called on a case-by-case basis, and can get repeatedly called for recursive // methods triggering a loop. Unfortunately the callStack is not pervasive @@ -2362,7 +2363,7 @@ TR_ParameterToArgumentMapper::initialize(TR_CallStack *callStack) TR::SymbolReference * symRef = NULL; const static bool disableUseKnownObjectTempsForParms = feGetEnv("TR_DisableUseKnownObjectTempsForParmsInCallee") ? true: false; int argOrdinal = argIndex - _callNode->getFirstArgumentIndex(); - TR_PrexArgument * prexArgument = _argInfo->get(argOrdinal); + TR_PrexArgument * prexArgument = _argInfo ? _argInfo->get(argOrdinal) : NULL; // use known object temp if the argument is a known object if (!disableUseKnownObjectTempsForParms && prexArgument && !parmMap->_parmIsModified @@ -4600,7 +4601,8 @@ void TR_InlinerBase::inlineFromGraph(TR_CallStack *prevCallStack, TR_CallTarget for (int32_t i = 0; i < site->numTargets(); i++) { TR_CallTarget *target = site->getTarget(i); - getUtil()->computePrexInfo(target, calltarget->_prexArgInfo); + // Compute arg info for target to inline, and propagate caller's arg info into callee + target->_prexArgInfo = getUtil()->computePrexInfo(target, calltarget->_prexArgInfo); targetsToInline.add(target); } } @@ -5688,6 +5690,17 @@ TR_CallSite::addTarget(TR_Memory* mem, TR_InlinerBase *inliner, TR_VirtualGuardS { TR_PrexArgInfo *myPrexArgInfo = inliner->getUtil()->createPrexArgInfoForCallTarget(guard, implementer); + // Merge call site prex arginfo into `myPrexArgInfo` + if (myPrexArgInfo && _ecsPrexArgInfo) + { + TR_PrexArgInfo::enhance(myPrexArgInfo, _ecsPrexArgInfo, _comp); + } + else if (_ecsPrexArgInfo) + { + // Clone call site prex arg info + myPrexArgInfo = new (comp()->trHeapMemory()) TR_PrexArgInfo(_ecsPrexArgInfo, comp()->trMemory()); + } + TR_CallTarget *result = new (mem,allocKind) TR_CallTarget(this,_initialCalleeSymbol,implementer,guard,receiverClass,myPrexArgInfo,ratio); addTarget(result); @@ -6365,15 +6378,9 @@ OMR_InlinerUtil::computePrexInfo(TR_CallTarget *target, TR_PrexArgInfo *callerAr /** * \brief * Clear non-invariant argument arg info for target - * - * \parm target - * Call target whose arg info is to be cleared for non-invariant arguments - * - * \parm tracer - * Inliner tracer used for trace message */ void -OMR_InlinerUtil::clearArgInfoForNonInvariantArguments(TR_CallTarget *target, TR_InlinerTracer* tracer) +OMR_InlinerUtil::clearArgInfoForNonInvariantArguments(TR_PrexArgInfo* argInfo, TR::ResolvedMethodSymbol* methodSymbol, TR_InlinerTracer* tracer) { if (comp()->getOption(TR_DisableInlinerArgsPropagation)) return; @@ -6382,13 +6389,12 @@ OMR_InlinerUtil::clearArgInfoForNonInvariantArguments(TR_CallTarget *target, TR_ if (tracePrex) traceMsg(comp(), "Clearing arg info for non invariant arguments\n"); - TR::ResolvedMethodSymbol* methodSymbol = target->_calleeSymbol; + TR_ASSERT(argInfo, "argInfo can't be NULL"); + TR_ASSERT(methodSymbol, "methodSymbol can't be NULL"); - TR_PrexArgInfo* argInfo = target->_prexArgInfo; - if (!argInfo) + if (!methodSymbol->getFirstTreeTop() && tracePrex) { - if (tracePrex) - traceMsg(comp(), "Prex arg info not avaiable\n"); + traceMsg(comp(), "IL trees are not generated for method, no arg info is cleared\n"); return; } @@ -6426,15 +6432,36 @@ OMR_InlinerUtil::clearArgInfoForNonInvariantArguments(TR_CallTarget *target, TR_ } } - if (cleanedAnything) + if (tracePrex) { - if (tracePrex) + if (cleanedAnything) + { traceMsg(comp(), "ARGS PROPAGATION: argInfo %p after clear arg info for non-invariant arguments", argInfo); - if (tracer->heuristicLevel()) - argInfo->dumpTrace(); + if (tracer->heuristicLevel()) + argInfo->dumpTrace(); + } + else + traceMsg(comp(), "ARGS PROPAGATION: Nothing is cleared\n"); } } +/** + * \brief + * Clear non-invariant argument arg info for target + * + * \parm target + * Call target whose arg info is to be cleared for non-invariant arguments + * + * \parm tracer + * Inliner tracer used for trace message + */ +void +OMR_InlinerUtil::clearArgInfoForNonInvariantArguments(TR_CallTarget *target, TR_InlinerTracer* tracer) + { + if (target->_prexArgInfo) + clearArgInfoForNonInvariantArguments(target->_prexArgInfo, target->_calleeSymbol, tracer); + } + bool OMR_InlinerUtil::needTargetedInlining(TR::ResolvedMethodSymbol *callee) { diff --git a/compiler/optimizer/Inliner.hpp b/compiler/optimizer/Inliner.hpp index 9918fc3a644..63a80c0b8e0 100644 --- a/compiler/optimizer/Inliner.hpp +++ b/compiler/optimizer/Inliner.hpp @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corp. and others + * Copyright (c) 2000, 2021 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -554,6 +554,7 @@ class OMR_InlinerUtil : public TR::OptimizationUtil, public OMR_InlinerHelper virtual TR_PrexArgInfo *computePrexInfo(TR_CallTarget *target); virtual TR_PrexArgInfo *computePrexInfo(TR_CallTarget *target, TR_PrexArgInfo *callerArgInfo); virtual void clearArgInfoForNonInvariantArguments(TR_CallTarget *target, TR_InlinerTracer* tracer); + virtual void clearArgInfoForNonInvariantArguments(TR_PrexArgInfo* argInfo, TR::ResolvedMethodSymbol* methodSymbol, TR_InlinerTracer* tracer); virtual void collectCalleeMethodClassInfo(TR_ResolvedMethod *calleeMethod); /* * Implemented by down stream projects to request for certain optimizations based on \parm target diff --git a/compiler/optimizer/PreExistence.cpp b/compiler/optimizer/PreExistence.cpp index 0ffae8352bc..69e79ff1df1 100644 --- a/compiler/optimizer/PreExistence.cpp +++ b/compiler/optimizer/PreExistence.cpp @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corp. and others + * Copyright (c) 2000, 2021 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -54,13 +54,17 @@ TR_PrexArgument::TR_PrexArgument( _knownObjectIndex(knownObjectIndex) { #ifdef J9_PROJECT_SPECIFIC - TR::VMAccessCriticalSection prexArgumentCriticalSection(comp, - TR::VMAccessCriticalSection::tryToAcquireVMAccess); - - if (prexArgumentCriticalSection.hasVMAccess()) + auto knot = comp->getKnownObjectTable(); + if (knot && !knot->isNull(knownObjectIndex)) { - _class = TR::Compiler->cls.objectClass(comp, comp->getKnownObjectTable()->getPointer(knownObjectIndex)); - _classKind = ClassIsFixed; + TR::VMAccessCriticalSection prexArgumentCriticalSection(comp, + TR::VMAccessCriticalSection::tryToAcquireVMAccess); + + if (prexArgumentCriticalSection.hasVMAccess()) + { + _class = TR::Compiler->cls.objectClass(comp, comp->getKnownObjectTable()->getPointer(knownObjectIndex)); + _classKind = ClassIsFixed; + } } #endif } @@ -84,3 +88,58 @@ void TR_PrexArgInfo::dumpTrace() { } traceMsg(comp, "\n"); } + +/** + * \brief + * Given two `TR_PrexArgument`, return the one with more concrete argument info + */ +static TR_PrexArgument *strongerArgumentInfo(TR_PrexArgument *left, TR_PrexArgument *right, TR::Compilation *comp) + { + if (TR_PrexArgument::knowledgeLevel(left) > TR_PrexArgument::knowledgeLevel(right)) + return left; + else if (TR_PrexArgument::knowledgeLevel(right) > TR_PrexArgument::knowledgeLevel(left)) + return right; + else if (left && right) + { + if (left->getClass() && right->getClass()) + { + if (comp->fe()->isInstanceOf(left->getClass(), right->getClass(), true, true, false)) + return left; + else if (comp->fe()->isInstanceOf(right->getClass(), left->getClass(), true, true, false)) + return right; + } + else if (left->getClass()) + return left; + else if (right->getClass()) + return right; + + return NULL; + } + else + return left ? left : right; // Return non-null prex argument when possible + } + +TR_PrexArgInfo * +TR_PrexArgInfo::enhance(TR_PrexArgInfo *dest, TR_PrexArgInfo *source, TR::Compilation *comp) + { + // If dest is NULL, we can't simply return source, as TR_PrexArgInfo is mutable, any + // future change to dest will change source. Thus return a copy of source + // + if (!dest && source) + return new (comp->trHeapMemory()) TR_PrexArgInfo(source, comp->trMemory()); + else if (!source) + return dest; + + TR_ASSERT(dest->getNumArgs() == source->getNumArgs(), "Number of arguments don't match: dest %p %d arguments and source %p %d arguments", dest, dest->getNumArgs(), source, source->getNumArgs()); + + auto numArgsToEnhance = dest->getNumArgs(); + for (int32_t i = 0; i < numArgsToEnhance; i++) + { + TR_PrexArgument* result = strongerArgumentInfo(dest->get(i), source->get(i), comp); + if (result) + dest->set(i, result); + } + + return dest; + } + diff --git a/compiler/optimizer/PreExistence.hpp b/compiler/optimizer/PreExistence.hpp index b84c143f23a..30824199f5e 100644 --- a/compiler/optimizer/PreExistence.hpp +++ b/compiler/optimizer/PreExistence.hpp @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corp. and others + * Copyright (c) 2000, 2021 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -34,6 +34,7 @@ class TR_OpaqueClassBlock; class TR_VirtualGuard; namespace TR { class Compilation; } namespace TR { class Node; } +namespace TR { class TreeTop; } namespace TR { class ResolvedMethodSymbol; } enum PrexKnowledgeLevel { NONE, PREEXISTENT, FIXED_CLASS, KNOWN_OBJECT }; @@ -106,8 +107,15 @@ class TR_PrexArgInfo { public: -#ifdef J9_PROJECT_SPECIFIC + /** + * \brief + * Improve prex arg info `dest` with `source` + * + * \return + * TR_PrexArgInfo The improved prex arg info + */ static TR_PrexArgInfo* enhance(TR_PrexArgInfo *dest, TR_PrexArgInfo *source, TR::Compilation *comp); +#ifdef J9_PROJECT_SPECIFIC static void propagateReceiverInfoIfAvailable (TR::ResolvedMethodSymbol* methodSymbol, TR_CallSite* callsite, TR_PrexArgInfo* argInfo, TR_LogTracer* tracer); @@ -136,12 +144,22 @@ class TR_PrexArgInfo memset(_args, 0, sizeof(TR_PrexArgument*) * numArgs); } + // Construct TR_PrexArgInfo from another TR_PrexArgInfo + TR_PrexArgInfo(TR_PrexArgInfo* other, TR_Memory * m) + { + TR_ASSERT(other, "other can't be NULL"); + _numArgs = other->_numArgs; + _args = (TR_PrexArgument **) m->allocateHeapMemory(sizeof(TR_PrexArgument*) * _numArgs); + memcpy(_args, other->_args, sizeof(TR_PrexArgument*) * _numArgs); + } + void set(int32_t index, TR_PrexArgument *info) { _args[index] = info; } TR_PrexArgument *get(int32_t index) { return _args[index]; } int32_t getNumArgs() { return _numArgs; } void dumpTrace(); + static TR::TreeTop* getCallTree(TR::ResolvedMethodSymbol* methodSymbol, TR_CallSite* callsite, TR_LogTracer* tracer); private: