Path: blob/master/runtime/compiler/optimizer/InterpreterEmulator.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/*23* \class InterpreterEmulator24*25* \brief This class is a bytecode iterator in estimate code size (ECS) of inliner.26*27* \notes The iterator has statelss and with state modes.28*29* Stateless mode is the default mode and can be used to iterate30* through bytecodes in the method. This mode is currently used in the31* in ECS for \ref processBytecodeAndGenerateCFG for all methods and32* \ref findAndCreateCallsitesFromBytecodes when the target is not a methodhandle33* thunk archetype.34*35* With state mode is used to emulate the interpreter execution with36* an operand stack maintained during bytecode iteration to keep useful37* information like known object and constant integer so38* that inliner can make better decision when creating callsites. For39* example, inliner can avoid creating callsites on dead path40* \ref maintainStackForIf or can refine callee method based on known41* receiver info \ref refineResolvedCalleeForInvokestatic. Operands that42* can't be reasoned about are represented by a dummy operand \ref _unknownOperand43* which doesn't carry any extra information. Currently, with state mode only44* supports methodhandle thunk archetypes.45*/4647#ifndef INTERPRETER_EMULATOR_INCL48#define INTERPRETER_EMULATOR_INCL4950#include "compile/Compilation.hpp"51#include "env/TRMemory.hpp"52#include "il/Block.hpp"53#include "ilgen/ByteCodeIteratorWithState.hpp"54#include "ilgen/J9ByteCodeIterator.hpp"55#include "infra/String.hpp"56#include "optimizer/Inliner.hpp"57#include "optimizer/J9EstimateCodeSize.hpp"58#include "optimizer/J9Inliner.hpp"5960class IconstOperand;61class KnownObjOperand;62class MutableCallsiteTargetOperand;63class FixedClassOperand;64class PreexistentObjectOperand;65class ObjectOperand;66class TR_PrexArgument;6768/*69* \class Operand70*71* \brief represent an operand on the operand stack72*73* \note this is the most general operand which doesn't carry any specific information.74*/75class Operand76{77public:78TR_ALLOC(TR_Memory::EstimateCodeSize);7980enum KnowledgeLevel { NONE, OBJECT, MUTABLE_CALLSITE_TARGET, PREEXISTENT, FIXED_CLASS, KNOWN_OBJECT, ICONST };81static const char* KnowledgeStrings[];8283virtual IconstOperand* asIconst(){ return NULL;}84virtual KnownObjOperand *asKnownObject(){ return NULL;}85virtual FixedClassOperand *asFixedClassOperand(){ return NULL;}86virtual PreexistentObjectOperand *asPreexistentObjectOperand(){ return NULL;}87virtual ObjectOperand *asObjectOperand(){ return NULL;}88virtual MutableCallsiteTargetOperand* asMutableCallsiteTargetOperand(){ return NULL;}89virtual TR::KnownObjectTable::Index getKnownObjectIndex(){ return TR::KnownObjectTable::UNKNOWN;}90virtual char* getSignature(TR::Compilation *comp, TR_Memory *trMemory) {return NULL;}91virtual void printToString(TR::StringBuf *buf);92virtual KnowledgeLevel getKnowledgeLevel() { return NONE; }93Operand* merge(Operand* other);94virtual Operand* merge1(Operand* other);95};9697class IconstOperand : public Operand98{99public:100TR_ALLOC(TR_Memory::EstimateCodeSize);101IconstOperand (int x): intValue(x) { }102virtual IconstOperand *asIconst() { return this;}103virtual void printToString(TR::StringBuf *buf);104int32_t intValue;105106virtual KnowledgeLevel getKnowledgeLevel() { return ICONST; }107virtual Operand* merge1(Operand* other);108};109110111/*112* \class ObjectOperand113*114* \brief Represent a java object115*/116class ObjectOperand : public Operand117{118public:119TR_ALLOC(TR_Memory::EstimateCodeSize);120ObjectOperand(TR_OpaqueClassBlock* clazz = NULL):121_signature(NULL), _clazz(clazz) {}122virtual char* getSignature(TR::Compilation *comp, TR_Memory *trMemory);123virtual ObjectOperand *asObjectOperand(){ return this;}124virtual TR_OpaqueClassBlock* getClass() { return _clazz;}125virtual KnowledgeLevel getKnowledgeLevel() { return OBJECT; }126virtual Operand* merge1(Operand* other);127virtual void printToString(TR::StringBuf *buf);128129protected:130char* _signature;131TR_OpaqueClassBlock* _clazz;132};133134/*135* \class PreexistentObjectOperand136*137* \brief Represent an object that preexist before the compiled method, i.e. it is138* a parm of the compiled method.139*/140class PreexistentObjectOperand : public ObjectOperand141{142public:143TR_ALLOC(TR_Memory::EstimateCodeSize);144PreexistentObjectOperand(TR_OpaqueClassBlock* clazz):ObjectOperand(clazz){ }145virtual PreexistentObjectOperand *asPreexistentObjectOperand(){ return this;}146virtual KnowledgeLevel getKnowledgeLevel() { return PREEXISTENT; }147virtual Operand* merge1(Operand* other);148};149150/*151* \class FixedClassOperand152*153* \brief An object with known type154*/155class FixedClassOperand : public ObjectOperand156{157public:158TR_ALLOC(TR_Memory::EstimateCodeSize);159FixedClassOperand(TR_OpaqueClassBlock* clazz):ObjectOperand(clazz){ }160virtual FixedClassOperand *asFixedClassOperand(){ return this;}161virtual KnowledgeLevel getKnowledgeLevel() { return FIXED_CLASS; }162virtual Operand* merge1(Operand* other);163};164165/*166* \class KnownObjOperand167*168* \brief Represent an object with known identity at compile time169*/170class KnownObjOperand : public FixedClassOperand171{172public:173TR_ALLOC(TR_Memory::EstimateCodeSize);174KnownObjOperand(TR::KnownObjectTable::Index koi, TR_OpaqueClassBlock* clazz = NULL);175virtual KnownObjOperand *asKnownObject(){ return this;}176virtual FixedClassOperand *asFixedClassOperand();177virtual ObjectOperand *asObjectOperand();178virtual TR_OpaqueClassBlock* getClass();179virtual TR::KnownObjectTable::Index getKnownObjectIndex(){ return knownObjIndex;}180virtual KnowledgeLevel getKnowledgeLevel() { return KNOWN_OBJECT; }181virtual Operand* merge1(Operand* other);182virtual void printToString(TR::StringBuf *buf);183private:184TR::KnownObjectTable::Index knownObjIndex;185};186187/*188* \class MutableCallsiteTargetOperand189*190* \note This class is used to support mutable callsite because both the methodhandle object191* and the mutable callsite needs to be tracked so that when creating \c TR_J9MutableCallSite192* the mutable callsite object can be set for the callsite even though it's really the193* methodhandle object that's on the operand stack.194*195* \see getReturnValue196* \see refineResolvedCalleeForInvokestatic197* \see visitInvokestatic198*/199class MutableCallsiteTargetOperand : public ObjectOperand200{201public:202TR_ALLOC(TR_Memory::EstimateCodeSize);203MutableCallsiteTargetOperand (TR::KnownObjectTable::Index methodHandleIndex, TR::KnownObjectTable::Index mutableCallsiteIndex):204methodHandleIndex(methodHandleIndex),205mutableCallsiteIndex(mutableCallsiteIndex){}206virtual MutableCallsiteTargetOperand* asMutableCallsiteTargetOperand(){ return this; }207virtual Operand* merge1(Operand* other);208virtual void printToString(TR::StringBuf *buf);209virtual KnowledgeLevel getKnowledgeLevel() { return MUTABLE_CALLSITE_TARGET; }210TR::KnownObjectTable::Index getMethodHandleIndex(){ return methodHandleIndex; }211TR::KnownObjectTable::Index getMutableCallsiteIndex() { return mutableCallsiteIndex; }212TR::KnownObjectTable::Index mutableCallsiteIndex;213TR::KnownObjectTable::Index methodHandleIndex;214};215216class InterpreterEmulator : public TR_ByteCodeIteratorWithState<TR_J9ByteCode, J9BCunknown, TR_J9ByteCodeIterator, Operand *>217{218typedef TR_ByteCodeIteratorWithState<TR_J9ByteCode, J9BCunknown, TR_J9ByteCodeIterator, Operand *> Base;219220public:221InterpreterEmulator(222TR_CallTarget *calltarget,223TR::ResolvedMethodSymbol * methodSymbol,224TR_J9VMBase * fe,225TR::Compilation * comp,226TR_LogTracer *tracer,227TR_EstimateCodeSize *ecs)228: Base(methodSymbol, comp),229_calltarget(calltarget),230_tracer(tracer),231_ecs(ecs),232_iteratorWithState(false)233{234TR_J9ByteCodeIterator::initialize(static_cast<TR_ResolvedJ9Method *>(methodSymbol->getResolvedMethod()), fe);235_flags = NULL;236_stacks = NULL;237_currentLocalObjectInfo = NULL;238_localObjectInfos = NULL;239_currentCallSite = NULL;240_currentCallMethod = NULL;241_currentCallMethodUnrefined = NULL;242_numSlots = 0;243_callerIsThunkArchetype = _calltarget->_calleeMethod->convertToMethod()->isArchetypeSpecimen();244245_operandBuf = NULL;246if (_tracer->heuristicLevel() || _tracer->debugLevel())247{248TR::Region &stackRegion = comp->trMemory()->currentStackRegion();249_operandBuf = new (stackRegion) TR::StringBuf(stackRegion);250}251}252TR_LogTracer *tracer() { return _tracer; }253/* \brief Initialize data needed for looking for callsites254*255* \param blocks256* blocks generated from bytecodes257*258* \param flags259* flags with bits to indicate property of each bytecode. The flags are set by \ref TR_J9EstimateCodeSize::processBytecodeAndGenerateCFG.260*261* \param callSites262* the call sites array to be filled in with callsites found263*264* \param cfg265* CFG generated \ref TR_J9EstimateCodeSize::processBytecodeAndGenerateCFG from bytecodes266*267* \param recursionDepth268* the depth of inlining layers269*270* \parm callstack271* the call stack from the current inlined call target to the method being compiled272*/273void prepareToFindAndCreateCallsites(TR::Block **blocks, flags8_t * flags, TR_CallSite ** callSites, TR::CFG* cfg, TR_ByteCodeInfo *newBCInfo, int32_t recursionDepth, TR_CallStack *callstack);274275/*276* \brief look for calls in bytecodes and create callsites277*278* \param wasPeekingSuccessfull279* indicate whether trees has been generated by peeking ilgen280*281* \param withState282* whether the bytecode iteration should be with or without state283*284* \return whether callsites are created successfully. Return false if failed for reasons like unexpected bytecodes etc.285*/286bool findAndCreateCallsitesFromBytecodes(bool wasPeekingSuccessfull, bool withState);287void setBlocks(TR::Block **blocks) { _blocks = blocks; }288TR_StackMemory trStackMemory() { return _trMemory; }289290/*291* \brief Compute prex arg info for the given call site292*/293TR_PrexArgInfo* computePrexInfo(294TR_CallSite *callsite, TR::KnownObjectTable::Index appendix);295TR_PrexArgument* createPrexArgFromOperand(Operand* operand);296Operand* createOperandFromPrexArg(TR_PrexArgument* arg);297298bool _nonColdCallExists;299bool _inlineableCallExists;300301enum BytecodePropertyFlag302{303bbStart = 0x01, // whether the current bytecode is at bbstart304isCold = 0x02, // whther the bytecode is on a cold path305isBranch = 0x04, // whther the bytecode is a branch306isUnsanitizeable = 0x08,307};308309private:310// the following methods can only be called when the iterator has state311312/*313* Initialize the data structures needed for iterator with state314*/315void initializeIteratorWithState();316/*317* push and pop operands on stack according to given bytecode318*319* \return false if some error occurred such as unexpected bytecodes.320*/321bool maintainStack(TR_J9ByteCode bc);322void maintainStackForIf(TR_J9ByteCode bc);323void maintainStackForGetField();324void maintainStackForAload(int slotIndex);325void maintainStackForReturn();326/*327* \brief helper to pop arguments from the stack and push the result for calls328*329* \param numArgs330* Number of arguments of the call331*332* \param result333* the operand reprenting the call return value334*335* \param returnType336* Return type of the call337*/338void maintainStackForCall(Operand *result, int32_t numArgs, TR::DataType returnType);339/*340* \brief helper to pop arguments from the stack and push the result for calls341*/342void maintainStackForCall();343/*344* \brief refine invokestatic callee method based on operands when possible345*/346void refineResolvedCalleeForInvokestatic(TR_ResolvedMethod *&callee, TR::KnownObjectTable::Index & mcsIndex, TR::KnownObjectTable::Index & mhIndex, bool & isIndirectCall);347/*348* \brief refine invokevirtual callee method based on operands when possible349*/350void refineResolvedCalleeForInvokevirtual(TR_ResolvedMethod*& callee, bool &isIndirectCall);351/*352* \brief Compute result of the given call based on operand stack state353*/354Operand *getReturnValue(TR_ResolvedMethod *callee);355void dumpStack();356void pushUnknownOperand() { Base::push(_unknownOperand); }357// doesn't need to handle execeptions yet as they don't exist in method handle thunk archetypes358virtual void findAndMarkExceptionRanges(){ }359/*360* \brief Propagte state state and local variable state to next target361*/362virtual void saveStack(int32_t targetIndex);363364// the following methods can be used in both stateless and with state mode365366/*367* \brief look for and set the next bytecode index to visit368*369* \return the bytecode value to visit370*/371TR_J9ByteCode findNextByteCodeToVisit();372373/*374* \brief tell whether the given bcIndex has been generated.375*376* \note This query is used to avoid regenerating bytecodes which shouldn't happen at stateless mode377*/378bool isGenerated(int32_t bcIndex) { return _iteratorWithState ? Base::isGenerated(bcIndex): false; }379/*380* \brief Set up operand stack and local slot array for block starting at given bytecode index381*382* \param index383* Bytecode index at the block entry384*/385virtual int32_t setupBBStartContext(int32_t index);386/*387* \brief set up object info in local slots at entry of a block388*389* \param index390* Bytecode index at the block entry391*/392void setupBBStartLocalObjectState(int32_t index);393/*394* \brief set up object info in local slots for the method entry395*/396void setupMethodEntryLocalObjectState();397/*398* \brief set up operand stack state at entry of a block399*400* \param index401* Bytecode index at the block entry402*/403void setupBBStartStackState(int32_t index);404405void visitInvokedynamic();406void visitInvokevirtual();407#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)408void visitInvokehandle();409void updateKnotAndCreateCallSiteUsingInvokeCacheArray(TR_ResolvedJ9Method* owningMethod, uintptr_t * invokeCacheArray, int32_t cpIndex);410#endif411void visitInvokespecial();412void visitInvokestatic();413void visitInvokeinterface();414void findTargetAndUpdateInfoForCallsite(415TR_CallSite *callsite,416TR::KnownObjectTable::Index appendix = TR::KnownObjectTable::UNKNOWN);417bool isCurrentCallUnresolvedOrCold(TR_ResolvedMethod *resolvedMethod, bool isUnresolvedInCP);418void debugUnresolvedOrCold(TR_ResolvedMethod *resolvedMethod);419void maintainStackForAstore(int slotIndex);420void maintainStackForldc(int32_t cpIndex);421void maintainStackForGetStatic();422/*423* \brief Check if a block has predecessors whose bytecodes haven't been visited424*/425bool hasUnvisitedPred(TR::Block* block);426427typedef TR_Array<Operand*> OperandArray;428void printOperandArray(OperandArray* operands);429/*430* \brief Merge second operand into the first, does an intersect operand on every operand in the array431*/432void mergeOperandArray(OperandArray *first, OperandArray *second);433434435TR_LogTracer *_tracer;436TR_EstimateCodeSize *_ecs;437Operand * _unknownOperand; // used whenever the iterator can't reason about an operand438TR_CallTarget *_calltarget; // the target method to inline439bool _iteratorWithState;440flags8_t * _InterpreterEmulatorFlags; // flags with bits to indicate property of each bytecode.441TR_CallSite ** _callSites;442TR_CallSite * _currentCallSite; // Store created callsite if visiting invoke* bytecodes443TR_ResolvedMethod * _currentCallMethod; // Resolved method for invoke* bytecodes, some calls won't have call site created due to coldness info444TR_ResolvedMethod * _currentCallMethodUnrefined; // Call method without any refinement applied to it445TR::CFG* _cfg;446TR_ByteCodeInfo *_newBCInfo;447int32_t _recursionDepth;448TR_CallStack *_callStack; // the call stack from the current inlined call target to the method being compiled449bool _wasPeekingSuccessfull;450TR::Block *_currentInlinedBlock;451TR_prevArgs _pca;452453bool _callerIsThunkArchetype;454// State of local object for current bytecode being visited455OperandArray* _currentLocalObjectInfo;456// Array of local object info arrays, indexed by bytecode index457OperandArray** _localObjectInfos;458// Number of local slots459int32_t _numSlots;460461TR::StringBuf *_operandBuf; // for debug printing462};463#endif464465466