Path: blob/master/runtime/compiler/optimizer/InterpreterEmulator.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2000, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/21#include "optimizer/InterpreterEmulator.hpp"22#include "optimizer/J9EstimateCodeSize.hpp"23#include "env/VMAccessCriticalSection.hpp"24#include "env/JSR292Methods.h"25#include "optimizer/PreExistence.hpp"26#include "optimizer/J9CallGraph.hpp"27#include "ilgen/IlGenRequest.hpp"28#include "jilconsts.h"29#include "il/ParameterSymbol.hpp"30#include "optimizer/PreExistence.hpp"31#include "optimizer/TransformUtil.hpp"32#include "il/Node_inlines.hpp"33#if defined(J9VM_OPT_JITSERVER)34#include "control/CompilationRuntime.hpp"35#include "env/j9methodServer.hpp"36#endif /* defined(J9VM_OPT_JITSERVER) */3738const char* Operand::KnowledgeStrings[] = {"NONE", "OBJECT", "MUTABLE_CALLSITE_TARGET", "PREEXISTENT", "FIXED_CLASS", "KNOWN_OBJECT", "ICONST" };3940char*41ObjectOperand::getSignature(TR::Compilation *comp, TR_Memory *trMemory)42{43if (!_signature && _clazz)44_signature = TR::Compiler->cls.classSignature(comp, _clazz, trMemory);45return _signature;46}4748KnownObjOperand::KnownObjOperand(TR::KnownObjectTable::Index koi, TR_OpaqueClassBlock* clazz)49: knownObjIndex(koi), FixedClassOperand(clazz)50{51TR_ASSERT_FATAL(knownObjIndex != TR::KnownObjectTable::UNKNOWN, "Unexpected unknown object");52}5354TR_OpaqueClassBlock*55KnownObjOperand::getClass()56{57if (_clazz)58return _clazz;5960TR::Compilation* comp = TR::comp();61auto knot = comp->getOrCreateKnownObjectTable();62if (!knot || knot->isNull(knownObjIndex))63return NULL;6465_clazz = comp->fej9()->getObjectClassFromKnownObjectIndex(comp, knownObjIndex);6667return _clazz;68}6970ObjectOperand*71KnownObjOperand::asObjectOperand()72{73if (getClass())74return this;7576return NULL;77}7879// FixedClassOperand need the class, if we can't get the class, return NULL80FixedClassOperand*81KnownObjOperand::asFixedClassOperand()82{83if (getClass())84return this;8586return NULL;87}8889Operand*90Operand::merge(Operand* other)91{92if (getKnowledgeLevel() > other->getKnowledgeLevel())93return other->merge1(this);94else95return merge1(other);96}9798Operand*99Operand::merge1(Operand* other)100{101if (this == other)102return this;103else104return NULL;105}106107Operand*108IconstOperand::merge1(Operand* other)109{110TR_ASSERT(other->getKnowledgeLevel() >= this->getKnowledgeLevel(), "Should be calling other->merge1(this)");111IconstOperand* otherIconst = other->asIconst();112if (otherIconst && this->intValue == otherIconst->intValue)113return this;114else115return NULL;116}117118// TODO: check instanceOf relationship and create new Operand if neccessary119Operand*120ObjectOperand::merge1(Operand* other)121{122TR_ASSERT(other->getKnowledgeLevel() >= this->getKnowledgeLevel(), "Should be calling other->merge1(this)");123ObjectOperand* otherObject = other->asObjectOperand();124if (otherObject && this->_clazz == otherObject->_clazz)125return this;126else127return NULL;128}129130// Both are preexistent objects131Operand*132PreexistentObjectOperand::merge1(Operand* other)133{134TR_ASSERT(other->getKnowledgeLevel() >= this->getKnowledgeLevel(), "Should be calling other->merge1(this)");135PreexistentObjectOperand* otherPreexistentObjectOperand = other->asPreexistentObjectOperand();136if (otherPreexistentObjectOperand && this->_clazz == otherPreexistentObjectOperand->_clazz)137return this;138else139return NULL;140}141142Operand*143FixedClassOperand::merge1(Operand* other)144{145TR_ASSERT(other->getKnowledgeLevel() >= this->getKnowledgeLevel(), "Should be calling other->merge1(this)");146FixedClassOperand* otherFixedClass = other->asFixedClassOperand();147if (otherFixedClass && this->_clazz == otherFixedClass->_clazz)148return this;149else150return NULL;151}152153Operand*154KnownObjOperand::merge1(Operand* other)155{156TR_ASSERT(other->getKnowledgeLevel() >= this->getKnowledgeLevel(), "Should be calling other->merge1(this)");157KnownObjOperand* otherKnownObj = other->asKnownObject();158if (otherKnownObj && this->knownObjIndex == otherKnownObj->knownObjIndex)159return this;160else161return NULL;162}163164Operand*165MutableCallsiteTargetOperand::merge1(Operand* other)166{167TR_ASSERT(other->getKnowledgeLevel() >= this->getKnowledgeLevel(), "Should be calling other->merge1(this)");168MutableCallsiteTargetOperand* otherMutableCallsiteTarget = other->asMutableCallsiteTargetOperand();169if (otherMutableCallsiteTarget &&170this->mutableCallsiteIndex== otherMutableCallsiteTarget->mutableCallsiteIndex &&171this->methodHandleIndex == otherMutableCallsiteTarget->methodHandleIndex)172return this;173else174return NULL;175}176177void178Operand::printToString(TR::StringBuf *buf)179{180buf->appendf("(unknown)");181}182183void184IconstOperand::printToString(TR::StringBuf *buf)185{186buf->appendf("(iconst=%d)", intValue);187}188189void190ObjectOperand::printToString(TR::StringBuf *buf)191{192buf->appendf("(%s=clazz%p)", KnowledgeStrings[getKnowledgeLevel()], getClass());193}194195void196KnownObjOperand::printToString(TR::StringBuf *buf)197{198buf->appendf("(obj%d)", getKnownObjectIndex());199}200201void202MutableCallsiteTargetOperand::printToString(TR::StringBuf *buf)203{204buf->appendf("(mh=%d, mcs=%d)", getMethodHandleIndex(), getMutableCallsiteIndex());205}206207void208InterpreterEmulator::printOperandArray(OperandArray* operands)209{210int32_t size = operands->size();211for (int32_t i = 0; i < size; i++)212{213_operandBuf->clear();214(*operands)[i]->printToString(_operandBuf);215traceMsg(comp(), "[%d]=%s, ", i, _operandBuf->text());216}217if (size > 0)218traceMsg(comp(), "\n");219}220221// Merge second OperandArray into the first one222// The merge does a union223//224void InterpreterEmulator::mergeOperandArray(OperandArray *first, OperandArray *second)225{226bool enableTrace = tracer()->debugLevel();227if (enableTrace)228{229traceMsg(comp(), "Operands before merging:\n");230printOperandArray(first);231}232233bool changed = false;234for (int i = 0; i < _numSlots; i++)235{236Operand* firstObj = (*first)[i];237Operand* secondObj = (*second)[i];238239firstObj = firstObj->merge(secondObj);240if (firstObj == NULL)241firstObj = _unknownOperand;242243if (firstObj != (*first)[i])244changed = true;245}246247if (enableTrace)248{249if (changed)250{251traceMsg(comp(), "Operands after merging:\n");252printOperandArray(first);253}254else255traceMsg(comp(), "Operands is not changed after merging\n");256}257}258259void260InterpreterEmulator::maintainStackForIf(TR_J9ByteCode bc)261{262TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");263TR_ASSERT_FATAL(bc == J9BCificmpeq || bc == J9BCificmpne, "InterpreterEmulator::maintainStackForIf can only be called with J9BCificmpeq and J9BCificmpne\n");264int32_t branchBC = _bcIndex + next2BytesSigned();265int32_t fallThruBC = _bcIndex + 3;266IconstOperand * second = pop()->asIconst();267IconstOperand * first = pop()->asIconst();268bool canBranch = true;269bool canFallThru = true;270// Comment out the branch folding as all the paths have to be interpreted in order271// to propagate object info in operand stack or local slots. Since branch folding272// currently only affects thunk archetypes, with similar branch folding in ilgen,273// calls in dead path won't be inlined, disabling the following code doesn't affect274// performance275// TODO: add code to record dead path and ignore it in object info propagation, enable276// the following code if branch folding is possible in LambdaForm methods277//278if (false && second && first)279{280switch (bc)281{282case J9BCificmpeq:283canBranch = second->intValue == first->intValue;284debugTrace(tracer(), "maintainStackForIf ifcmpeq %d == %d\n", second->intValue, first->intValue);285break;286case J9BCificmpne:287canBranch = second->intValue != first->intValue;288debugTrace(tracer(), "maintainStackForIf ifcmpne %d != %d\n", second->intValue, first->intValue);289break;290291default:292break;293}294canFallThru = !canBranch;295}296297// The branch target can be successor of the fall through, so gen fall through block first such298// that the predecessor is interpreted before the successor in order to propagate the operand299// stack and local slots state.300// This doesn't work when the fall through contain control flow, but there is no functional issue301// as the object info won't be propagated if there exists unvisited predecessor. This will be302// fixed when we traverse the bytecodes in reverse post order at CFG level.303//304if (canFallThru)305{306debugTrace(tracer(), "maintainStackForIf canFallThrough to bcIndex=%d\n", fallThruBC);307genTarget(fallThruBC);308}309310if (canBranch)311{312debugTrace(tracer(), "maintainStackForIf canBranch to bcIndex=%d\n", branchBC);313genTarget(branchBC);314}315316}317318void319InterpreterEmulator::maintainStackForGetField()320{321TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");322TR::DataType type = TR::NoType;323uint32_t fieldOffset;324int32_t cpIndex = next2Bytes();325Operand *newOperand = _unknownOperand;326TR::Symbol *fieldSymbol = TR::Symbol::createPossiblyRecognizedShadowFromCP(327comp(), trStackMemory(), _calltarget->_calleeMethod, cpIndex, &type, &fieldOffset, false);328329TR::KnownObjectTable *knot = comp()->getKnownObjectTable();330if (knot &&331top()->asKnownObject() &&332!knot->isNull(top()->getKnownObjectIndex())333&& type == TR::Address)334{335if (fieldSymbol == NULL)336{337debugTrace(tracer(), "field is unresolved");338}339else if (!comp()->fej9()->canDereferenceAtCompileTimeWithFieldSymbol(fieldSymbol, cpIndex, _calltarget->_calleeMethod))340{341debugTrace(tracer(), "field is not foldable");342}343else344{345TR::KnownObjectTable::Index baseObjectIndex = top()->getKnownObjectIndex();346TR::KnownObjectTable::Index resultIndex = TR::KnownObjectTable::UNKNOWN;347uintptr_t baseObjectAddress = 0;348uintptr_t fieldAddress = 0;349bool avoidFolding = true;350351#if defined(J9VM_OPT_JITSERVER)352if (comp()->isOutOfProcessCompilation())353{354TR_ResolvedJ9JITServerMethod *serverMethod = static_cast<TR_ResolvedJ9JITServerMethod*>(_calltarget->_calleeMethod);355TR_ResolvedMethod *clientMethod = serverMethod->getRemoteMirror();356357auto stream = TR::CompilationInfo::getStream();358stream->write(JITServer::MessageType::KnownObjectTable_dereferenceKnownObjectField,359baseObjectIndex, clientMethod, cpIndex);360361auto recv = stream->read<TR::KnownObjectTable::Index, uintptr_t*, uintptr_t, uintptr_t, bool>();362resultIndex = std::get<0>(recv);363uintptr_t *objectPointerReference = std::get<1>(recv);364fieldAddress = std::get<2>(recv);365baseObjectAddress = std::get<3>(recv);366avoidFolding = std::get<4>(recv);367368if (resultIndex != TR::KnownObjectTable::UNKNOWN)369knot->updateKnownObjectTableAtServer(resultIndex, objectPointerReference);370}371else372#endif /* defined(J9VM_OPT_JITSERVER) */373{374TR::VMAccessCriticalSection dereferenceKnownObjectField(comp()->fej9());375baseObjectAddress = knot->getPointer(baseObjectIndex);376TR_OpaqueClassBlock *baseObjectClass = comp()->fej9()->getObjectClass(baseObjectAddress);377TR_OpaqueClassBlock *fieldDeclaringClass = _calltarget->_calleeMethod->getDeclaringClassFromFieldOrStatic(comp(), cpIndex);378379avoidFolding = TR::TransformUtil::avoidFoldingInstanceField(380baseObjectAddress, fieldSymbol, fieldOffset, cpIndex, _calltarget->_calleeMethod, comp());381382if (fieldDeclaringClass && comp()->fej9()->isInstanceOf(baseObjectClass, fieldDeclaringClass, true) == TR_yes)383{384fieldAddress = comp()->fej9()->getReferenceFieldAtAddress(baseObjectAddress + fieldOffset);385resultIndex = knot->getOrCreateIndex(fieldAddress);386}387}388389bool fail = resultIndex == TR::KnownObjectTable::UNKNOWN;390if (fail || avoidFolding)391{392int32_t len = 0;393debugTrace(394tracer(),395"%s field in obj%d: %s",396fail ? "failed to determine value of" : "avoid folding sometimes-foldable",397baseObjectIndex,398_calltarget->_calleeMethod->fieldName(cpIndex, len, this->trMemory()));399}400else401{402// It's OK to print fieldAddress and baseObjectAddress here even403// without VM access. There's no meaningful difference between:404// - printing the object's address, then allowing it to move; and405// - observing the objects's address, then allowing it to move,406// then finally printing the observed address.407newOperand = new (trStackMemory()) KnownObjOperand(resultIndex);408int32_t len = 0;409debugTrace(tracer(), "dereference obj%d (%p)from field %s(offset = %d) of base obj%d(%p)\n",410newOperand->getKnownObjectIndex(), (void *)fieldAddress, _calltarget->_calleeMethod->fieldName(cpIndex, len, this->trMemory()),411fieldOffset, baseObjectIndex, baseObjectAddress);412}413}414}415pop();416push(newOperand);417}418419void420InterpreterEmulator::saveStack(int32_t targetIndex)421{422if (!_iteratorWithState)423return;424425// Propagate stack state to successor426if (!_stack->isEmpty())427{428if (!_stacks[targetIndex])429_stacks[targetIndex] = new (trStackMemory()) ByteCodeStack(*_stack);430else431{432TR_ASSERT_FATAL(_stacks[targetIndex]->size() == _stack->size(), "operand stack from two paths must have the same size, predecessor bci %d target bci %d\n", _bcIndex, targetIndex);433mergeOperandArray(_stacks[targetIndex], _stack);434}435}436437// Propagate local object info to successor438if (_numSlots)439{440if (!_localObjectInfos[targetIndex])441_localObjectInfos[targetIndex] = new (trStackMemory()) OperandArray(*_currentLocalObjectInfo);442else443mergeOperandArray(_localObjectInfos[targetIndex], _currentLocalObjectInfo);444}445}446447void448InterpreterEmulator::initializeIteratorWithState()449{450_iteratorWithState = true;451_unknownOperand = new (trStackMemory()) Operand();452uint32_t size = this->maxByteCodeIndex() + 5;453_flags = (flags8_t *) this->trMemory()->allocateStackMemory(size * sizeof(flags8_t));454_stacks = (ByteCodeStack * *) this->trMemory()->allocateStackMemory(size * sizeof(ByteCodeStack *));455memset(_flags, 0, size * sizeof(flags8_t));456memset(_stacks, 0, size * sizeof(ByteCodeStack *));457_stack = new (trStackMemory()) TR_Stack<Operand *>(this->trMemory(), 20, false, stackAlloc);458_localObjectInfos = (OperandArray**) this->trMemory()->allocateStackMemory(size * sizeof(OperandArray *));459memset(_localObjectInfos, 0, size * sizeof(OperandArray *));460461int32_t numParmSlots = method()->numberOfParameterSlots();462_numSlots = numParmSlots + method()->numberOfTemps();463464genBBStart(0);465setupBBStartContext(0);466this->setIndex(0);467}468469void470InterpreterEmulator::setupMethodEntryLocalObjectState()471{472TR_PrexArgInfo *argInfo = _calltarget->_ecsPrexArgInfo;473if (argInfo)474{475TR_ASSERT_FATAL(argInfo->getNumArgs() == method()->numberOfParameters(), "Prex arg number should match parm number");476477if(tracer()->heuristicLevel())478{479heuristicTrace(tracer(), "Save argInfo to slot state array");480argInfo->dumpTrace();481}482483method()->makeParameterList(_methodSymbol);484ListIterator<TR::ParameterSymbol> parms(&_methodSymbol->getParameterList());485486// save prex arg into local var arrays487for (TR::ParameterSymbol *p = parms.getFirst(); p != NULL; p = parms.getNext())488{489int32_t ordinal = p->getOrdinal();490int32_t slotIndex = p->getSlot();491TR_PrexArgument *prexArgument = argInfo->get(ordinal);492if (!prexArgument)493{494(*_currentLocalObjectInfo)[slotIndex] = _unknownOperand;495}496else497{498auto operand = createOperandFromPrexArg(prexArgument);499if (operand)500{501(*_currentLocalObjectInfo)[slotIndex] = operand;502}503else504(*_currentLocalObjectInfo)[slotIndex] = _unknownOperand;505}506if (tracer()->heuristicLevel())507{508_operandBuf->clear();509(*_currentLocalObjectInfo)[slotIndex]->printToString(_operandBuf);510heuristicTrace(511tracer(),512"Creating operand %s for parm %d slot %d from PrexArgument %p",513_operandBuf->text(),514ordinal,515slotIndex,516prexArgument);517}518}519}520}521522bool523InterpreterEmulator::hasUnvisitedPred(TR::Block* block)524{525TR_PredecessorIterator pi(block);526for (TR::CFGEdge *edge = pi.getFirst(); edge != NULL; edge = pi.getNext())527{528TR::Block *fromBlock = toBlock(edge->getFrom());529auto fromBCIndex = fromBlock->getEntry()->getNode()->getByteCodeIndex();530if (!isGenerated(fromBCIndex))531{532return true;533}534}535536return false;537}538539void540InterpreterEmulator::setupBBStartStackState(int32_t index)541{542if (index == 0)543return;544545auto block = blocks(index);546auto stack = _stacks[index];547if (stack && hasUnvisitedPred(block))548{549heuristicTrace(tracer(), "block_%d at bc index %d has unvisited predecessor, setting stack operand info to unknown", block->getNumber(), index);550for (int32_t i = 0; i < stack->size(); ++i)551(*stack)[i] = _unknownOperand;552}553}554555void556InterpreterEmulator::setupBBStartLocalObjectState(int32_t index)557{558if (_numSlots == 0)559return;560561if (!_localObjectInfos[index])562{563_localObjectInfos[index] = new (trStackMemory()) OperandArray(trMemory(), _numSlots, false, stackAlloc);564for (int32_t i = 0; i < _numSlots; i++)565(*_localObjectInfos[index])[i] = _unknownOperand;566}567else if (hasUnvisitedPred(blocks(index)))568{569heuristicTrace(tracer(), "block_%d at bc index %d has unvisited predecessor, setting local object info to unknown", blocks(index)->getNumber(), index);570for (int32_t i = 0; i < _numSlots; i++)571(*_localObjectInfos[index])[i] = _unknownOperand;572}573574_currentLocalObjectInfo = _localObjectInfos[index];575576if (index == 0)577setupMethodEntryLocalObjectState();578}579580int32_t581InterpreterEmulator::setupBBStartContext(int32_t index)582{583if (_iteratorWithState)584{585setupBBStartStackState(index);586setupBBStartLocalObjectState(index);587}588Base::setupBBStartContext(index);589return index;590}591592bool593InterpreterEmulator::maintainStack(TR_J9ByteCode bc)594{595TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");596int slotIndex = -1;597switch (bc)598{599case J9BCgetfield: maintainStackForGetField(); break;600case J9BCaload0: slotIndex = 0; maintainStackForAload(slotIndex); break;601case J9BCaload1: slotIndex = 1; maintainStackForAload(slotIndex); break;602case J9BCaload2: slotIndex = 2; maintainStackForAload(slotIndex); break;603case J9BCaload3: slotIndex = 3; maintainStackForAload(slotIndex); break;604case J9BCaload: slotIndex = nextByte(); maintainStackForAload(slotIndex); break;605case J9BCaloadw: slotIndex = next2Bytes(); maintainStackForAload(slotIndex); break;606607case J9BCinvokespecial:608case J9BCinvokespecialsplit:609case J9BCinvokevirtual:610case J9BCinvokestatic:611case J9BCinvokestaticsplit:612case J9BCinvokedynamic:613case J9BCinvokehandle:614maintainStackForCall();615break;616case J9BCiconstm1: push (new (trStackMemory()) IconstOperand(-1)); break;617case J9BCiconst0: push (new (trStackMemory()) IconstOperand(0)); break;618case J9BCiconst1: push (new (trStackMemory()) IconstOperand(1)); break;619case J9BCiconst2: push (new (trStackMemory()) IconstOperand(2)); break;620case J9BCiconst3: push (new (trStackMemory()) IconstOperand(3)); break;621case J9BCiconst4: push (new (trStackMemory()) IconstOperand(4)); break;622case J9BCiconst5: push (new (trStackMemory()) IconstOperand(5)); break;623case J9BCifne:624push (new (trStackMemory()) IconstOperand(0));625maintainStackForIf(J9BCificmpne);626break;627case J9BCifeq:628push (new (trStackMemory()) IconstOperand(0));629maintainStackForIf(J9BCificmpeq);630break;631case J9BCgoto:632genTarget(bcIndex() + next2BytesSigned());633break;634case J9BCpop:635case J9BCputfield:636case J9BCputstatic:637pop();638break;639case J9BCladd:640case J9BCiadd:641case J9BCisub:642case J9BCiand:643popn(2);644pushUnknownOperand();645break;646case J9BCistore: case J9BClstore: case J9BCfstore: case J9BCdstore:647case J9BCistorew: case J9BClstorew: case J9BCfstorew: case J9BCdstorew:648case J9BCistore0: case J9BCistore1: case J9BCistore2: case J9BCistore3:649case J9BClstore0: case J9BClstore1: case J9BClstore2: case J9BClstore3:650case J9BCfstore0: case J9BCfstore1: case J9BCfstore2: case J9BCfstore3:651case J9BCdstore0: case J9BCdstore1: case J9BCdstore2: case J9BCdstore3:652pop();653break;654// Maintain stack for object store655case J9BCastorew: maintainStackForAstore(next2Bytes()); break;656case J9BCastore: maintainStackForAstore(nextByte()); break;657case J9BCastore0: maintainStackForAstore(0); break;658case J9BCastore1: maintainStackForAstore(1); break;659case J9BCastore2: maintainStackForAstore(2); break;660case J9BCastore3: maintainStackForAstore(3); break;661662case J9BCiload0: case J9BCiload1: case J9BCiload2: case J9BCiload3:663case J9BCdload0: case J9BCdload1: case J9BCdload2: case J9BCdload3:664case J9BClload0: case J9BClload1: case J9BClload2: case J9BClload3:665case J9BCfload0: case J9BCfload1: case J9BCfload2: case J9BCfload3:666case J9BCiloadw: case J9BClloadw: case J9BCfloadw: case J9BCdloadw:667case J9BCiload: case J9BClload: case J9BCfload: case J9BCdload:668pushUnknownOperand();669break;670case J9BCgetstatic:671maintainStackForGetStatic();672break;673case J9BCgenericReturn:674case J9BCReturnC:675case J9BCReturnS:676case J9BCReturnB:677case J9BCReturnZ:678maintainStackForReturn();679break;680case J9BCi2l:681break;682case J9BCcheckcast:683break;684case J9BCdup:685push(top());686break;687case J9BCldc:688maintainStackForldc(nextByte()); break;689default:690static const bool assertfatal = feGetEnv("TR_AssertFatalForUnexpectedBytecodeInMethodHandleThunk") ? true: false;691if (!assertfatal)692debugTrace(tracer(), "unexpected bytecode in thunk archetype %s (%p) at bcIndex %d %s (%d)\n", _calltarget->_calleeMethod->signature(comp()->trMemory()), _calltarget, bcIndex(), comp()->fej9()->getByteCodeName(nextByte(0)), bc);693else694TR_ASSERT_FATAL(0, "unexpected bytecode in thunk archetype %s (%p) at bcIndex %d %s (%d)\n", _calltarget->_calleeMethod->signature(comp()->trMemory()), _calltarget, bcIndex(), comp()->fej9()->getByteCodeName(nextByte(0)), bc);695696TR::DebugCounter::incStaticDebugCounter(comp(),697TR::DebugCounter::debugCounterName(comp(),698"InterpreterEmulator.unexpectedBytecode/(root=%s)/(%s)/bc=%d/%s",699comp()->signature(),700_calltarget->_calleeMethod->signature(comp()->trMemory()),701_bcIndex,702comp()->fej9()->getByteCodeName(nextByte(0)))703);704return false;705}706return true;707}708709void710InterpreterEmulator::maintainStackForReturn()711{712if (method()->returnType() != TR::NoType)713pop();714}715716void717InterpreterEmulator::maintainStackForGetStatic()718{719TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");720if (comp()->compileRelocatableCode())721{722pushUnknownOperand();723return;724}725726int32_t cpIndex = next2Bytes();727debugTrace(tracer(), "getstatic cpIndex %d", cpIndex);728729void * dataAddress;730bool isVolatile, isPrivate, isUnresolvedInCP, isFinal;731TR::DataType type = TR::NoType;732auto owningMethod = _calltarget->_calleeMethod;733bool resolved = owningMethod->staticAttributes(734comp(),735cpIndex,736&dataAddress,737&type,738&isVolatile,739&isFinal,740&isPrivate,741false,742&isUnresolvedInCP);743744TR::KnownObjectTable::Index knownObjectIndex = TR::KnownObjectTable::UNKNOWN;745if (resolved && isFinal && type == TR::Address)746{747knownObjectIndex = TR::TransformUtil::knownObjectFromFinalStatic(748comp(), owningMethod, cpIndex, dataAddress);749}750751if (knownObjectIndex != TR::KnownObjectTable::UNKNOWN)752push(new (trStackMemory()) KnownObjOperand(knownObjectIndex));753else754pushUnknownOperand();755}756757void758InterpreterEmulator::maintainStackForAload(int slotIndex)759{760TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");761762push((*_currentLocalObjectInfo)[slotIndex]);763}764765void766InterpreterEmulator::maintainStackForAstore(int slotIndex)767{768TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");769(*_currentLocalObjectInfo)[slotIndex] = pop();770}771772void773InterpreterEmulator::maintainStackForldc(int32_t cpIndex)774{775TR::DataType type = method()->getLDCType(cpIndex);776switch (type)777{778case TR::Address:779// TODO: should add a function to check if cp entry is unresolved for all constant780// not just for string. Currently only do it for string because it may be patched781// to a different object in OpenJDK MethodHandle implementation782//783if (method()->isStringConstant(cpIndex) && !method()->isUnresolvedString(cpIndex))784{785uintptr_t * location = (uintptr_t *)method()->stringConstant(cpIndex);786TR::KnownObjectTable *knot = comp()->getKnownObjectTable();787if (knot)788{789TR::KnownObjectTable::Index koi = knot->getOrCreateIndexAt(location);790push(new (trStackMemory()) KnownObjOperand(koi));791debugTrace(tracer(), "aload known obj%d from ldc %d", koi, cpIndex);792return;793}794}795break;796default:797break;798}799800pushUnknownOperand();801}802803void804InterpreterEmulator::maintainStackForCall(Operand *result, int32_t numArgs, TR::DataType returnType)805{806TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");807808for (int i = 1; i <= numArgs; i++)809pop();810811if (result)812push(result);813else if (returnType != TR::NoType)814pushUnknownOperand();815}816817void818InterpreterEmulator::maintainStackForCall()819{820TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");821int32_t numOfArgs = 0;822TR::DataType returnType = TR::NoType;823Operand* result = NULL;824825if (_currentCallMethod)826result = getReturnValue(_currentCallMethod);827828// If the caller is thunk archetype, the load of parm `argPlaceholder` can829// be expanded to loads of multiple arguments, so we can't pop the number830// of arguments of a refined call831//832if (_currentCallSite && !_callerIsThunkArchetype)833{834if (_currentCallSite->_isInterface)835{836numOfArgs = _currentCallSite->_interfaceMethod->numberOfExplicitParameters() + 1;837returnType = _currentCallSite->_interfaceMethod->returnType();838}839else if (_currentCallSite->_initialCalleeMethod)840{841numOfArgs = _currentCallSite->_initialCalleeMethod->numberOfParameters();842returnType = _currentCallSite->_initialCalleeMethod->returnType();843}844}845else846{847int32_t cpIndex = next2Bytes();848bool isStatic = false;849switch (current())850{851case J9BCinvokespecialsplit:852cpIndex |= J9_SPECIAL_SPLIT_TABLE_INDEX_FLAG;853break;854case J9BCinvokestaticsplit:855cpIndex |= J9_STATIC_SPLIT_TABLE_INDEX_FLAG;856case J9BCinvokestatic:857isStatic = true;858break;859case J9BCinvokedynamic:860case J9BCinvokehandle:861TR_ASSERT_FATAL(false, "Can't maintain stack for unresolved invokehandle");862break;863864default:865break;866}867TR::Method * calleeMethod = comp()->fej9()->createMethod(trMemory(), _calltarget->_calleeMethod->containingClass(), cpIndex);868numOfArgs = calleeMethod->numberOfExplicitParameters() + (isStatic ? 0 : 1);869returnType = calleeMethod->returnType();870}871maintainStackForCall(result, numOfArgs, returnType);872}873874void875InterpreterEmulator::dumpStack()876{877if (!tracer()->debugLevel())878return;879880debugTrace(tracer(), "operandStack after bytecode %d : %s ", _bcIndex, comp()->fej9()->getByteCodeName(nextByte(0)));881for (int i = 0; i < _stack->size(); i++ )882{883Operand *x = (*_stack)[i];884_operandBuf->clear();885x->printToString(_operandBuf);886debugTrace(tracer(), "[%d]=%s", i, _operandBuf->text());887}888}889890Operand *891InterpreterEmulator::getReturnValue(TR_ResolvedMethod *callee)892{893if (!callee)894return NULL;895Operand *result = NULL;896TR::RecognizedMethod recognizedMethod = callee->getRecognizedMethod();897TR::KnownObjectTable *knot = comp()->getKnownObjectTable();898899TR::IlGeneratorMethodDetails & details = comp()->ilGenRequest().details();900if (_callerIsThunkArchetype && details.isMethodHandleThunk())901{902J9::MethodHandleThunkDetails & thunkDetails = static_cast<J9::MethodHandleThunkDetails &>(details);903if (!thunkDetails.isCustom())904recognizedMethod = TR::unknownMethod;905}906907switch (recognizedMethod)908{909case TR::java_lang_invoke_ILGenMacros_isCustomThunk:910result = new (trStackMemory()) IconstOperand(1);911break;912case TR::java_lang_invoke_ILGenMacros_isShareableThunk:913result = new (trStackMemory()) IconstOperand(0);914break;915916#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)917case TR::java_lang_invoke_DelegatingMethodHandle_getTarget:918{919TR::KnownObjectTable::Index dmhIndex = top()->getKnownObjectIndex();920bool trace = tracer()->debugLevel();921TR::KnownObjectTable::Index targetIndex =922comp()->fej9()->delegatingMethodHandleTarget(comp(), dmhIndex, trace);923924if (targetIndex == TR::KnownObjectTable::UNKNOWN)925return NULL;926927result = new (trStackMemory()) KnownObjOperand(targetIndex);928break;929}930#endif931932case TR::java_lang_invoke_MutableCallSite_getTarget:933case TR::java_lang_invoke_Invokers_getCallSiteTarget:934{935// The CallSite object is always topmost on the stack.936TR::KnownObjectTable::Index callSiteIndex = top()->getKnownObjectIndex();937if (callSiteIndex == TR::KnownObjectTable::UNKNOWN)938return NULL;939940TR::KnownObjectTable::Index resultIndex = TR::KnownObjectTable::UNKNOWN;941const char * const mcsClassName = "java/lang/invoke/MutableCallSite";942const int mcsClassNameLen = (int)strlen(mcsClassName);943TR_OpaqueClassBlock *mutableCallsiteClass =944fe()->getSystemClassFromClassName(mcsClassName, mcsClassNameLen, true);945946debugTrace(tracer(), "potential MCS target: call site obj%d(*%p) mutableCallsiteClass %p\n", callSiteIndex, knot->getPointerLocation(callSiteIndex), mutableCallsiteClass);947if (mutableCallsiteClass)948{949if (recognizedMethod != TR::java_lang_invoke_MutableCallSite_getTarget)950{951TR_OpaqueClassBlock *callSiteType =952fe()->getObjectClassFromKnownObjectIndex(comp(), callSiteIndex);953if (callSiteType == NULL)954{955debugTrace(tracer(), "failed to determine concrete CallSite type");956return NULL;957}958else if (fe()->isInstanceOf(callSiteType, mutableCallsiteClass, true) != TR_yes)959{960debugTrace(tracer(), "not a MutableCallSite");961return NULL;962}963}964965#if defined(J9VM_OPT_JITSERVER)966if (comp()->isOutOfProcessCompilation())967{968auto stream = TR::CompilationInfo::getStream();969stream->write(JITServer::MessageType::KnownObjectTable_dereferenceKnownObjectField2, mutableCallsiteClass, callSiteIndex);970971auto recv = stream->read<TR::KnownObjectTable::Index, uintptr_t*>();972resultIndex = std::get<0>(recv);973uintptr_t *objectPointerReference = std::get<1>(recv);974975if (resultIndex != TR::KnownObjectTable::UNKNOWN)976{977knot->updateKnownObjectTableAtServer(resultIndex, objectPointerReference);978}979result = new (trStackMemory()) MutableCallsiteTargetOperand(resultIndex, callSiteIndex);980}981else982#endif /* defined(J9VM_OPT_JITSERVER) */983{984TR::VMAccessCriticalSection dereferenceKnownObjectField(comp()->fej9());985int32_t targetFieldOffset = comp()->fej9()->getInstanceFieldOffset(mutableCallsiteClass, "target", "Ljava/lang/invoke/MethodHandle;");986uintptr_t receiverAddress = knot->getPointer(callSiteIndex);987TR_OpaqueClassBlock *receiverClass = comp()->fej9()->getObjectClass(receiverAddress);988TR_ASSERT_FATAL(comp()->fej9()->isInstanceOf(receiverClass, mutableCallsiteClass, true) == TR_yes, "receiver of mutableCallsite_getTarget must be instance of MutableCallSite (*%p)", knot->getPointerLocation(callSiteIndex));989uintptr_t fieldAddress = comp()->fej9()->getReferenceFieldAt(receiverAddress, targetFieldOffset);990resultIndex = knot->getOrCreateIndex(fieldAddress);991result = new (trStackMemory()) MutableCallsiteTargetOperand(resultIndex, callSiteIndex);992}993}994}995break;996case TR::java_lang_invoke_DirectMethodHandle_internalMemberName:997case TR::java_lang_invoke_DirectMethodHandle_internalMemberNameEnsureInit:998{999Operand* mh = top();1000TR::KnownObjectTable::Index mhIndex = top()->getKnownObjectIndex();1001debugTrace(tracer(), "Known DirectMethodHandle koi %d\n", mhIndex);1002TR::KnownObjectTable *knot = comp()->getKnownObjectTable();1003if (knot && mhIndex != TR::KnownObjectTable::UNKNOWN && !knot->isNull(mhIndex))1004{1005TR::KnownObjectTable::Index memberIndex = comp()->fej9()->getMemberNameFieldKnotIndexFromMethodHandleKnotIndex(comp(), mhIndex, "member");1006debugTrace(tracer(), "Known internal member name koi %d\n", memberIndex);1007result = new (trStackMemory()) KnownObjOperand(memberIndex);1008}1009break;1010}1011case TR::java_lang_invoke_DirectMethodHandle_constructorMethod:1012{1013Operand* mh = top();1014TR::KnownObjectTable::Index mhIndex = top()->getKnownObjectIndex();1015debugTrace(tracer(), "Known DirectMethodHandle koi %d\n", mhIndex);1016TR::KnownObjectTable *knot = comp()->getKnownObjectTable();1017if (knot && mhIndex != TR::KnownObjectTable::UNKNOWN && !knot->isNull(mhIndex))1018{1019TR::KnownObjectTable::Index memberIndex = comp()->fej9()->getMemberNameFieldKnotIndexFromMethodHandleKnotIndex(comp(), mhIndex, "initMethod");1020debugTrace(tracer(), "Known internal member name koi %d\n", memberIndex);1021result = new (trStackMemory()) KnownObjOperand(memberIndex);1022}1023break;1024}10251026default:1027break;1028}1029return result;1030}10311032void1033InterpreterEmulator::refineResolvedCalleeForInvokestatic(TR_ResolvedMethod *&callee, TR::KnownObjectTable::Index & mcsIndex, TR::KnownObjectTable::Index & mhIndex, bool &isIndirectCall)1034{1035TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");1036if (!comp()->getOrCreateKnownObjectTable())1037return;10381039bool isVirtual = false;1040TR::RecognizedMethod rm = callee->getRecognizedMethod();1041switch (rm)1042{1043// refine the ILGenMacros_invokeExact* callees1044case TR::java_lang_invoke_ILGenMacros_invokeExact:1045case TR::java_lang_invoke_ILGenMacros_invokeExact_X:1046case TR::java_lang_invoke_ILGenMacros_invokeExactAndFixup:1047{1048int argNum = callee->numberOfExplicitParameters();1049if (argNum > 0)1050{1051Operand *operand = topn(argNum-1); // for the ILGenMacros_invokeExact* methods, the first argument is always the methodhandle object1052MutableCallsiteTargetOperand * mcsOperand = operand->asMutableCallsiteTargetOperand();1053if (mcsOperand)1054{1055mhIndex = mcsOperand->getMethodHandleIndex();1056mcsIndex = mcsOperand->getMutableCallsiteIndex();1057}1058else1059mhIndex = operand->getKnownObjectIndex();1060}10611062if (mhIndex != TR::KnownObjectTable::UNKNOWN)1063{1064debugTrace(tracer(), "refine java_lang_invoke_MethodHandle_invokeExact with obj%d to archetype specimen at bcIndex=%d\n", mhIndex, _bcIndex);1065callee = comp()->fej9()->createMethodHandleArchetypeSpecimen(this->trMemory(), comp()->getKnownObjectTable()->getPointerLocation(mhIndex), _calltarget->_calleeMethod);1066}1067return;1068}1069// refine the leaf method handle callees1070case TR::java_lang_invoke_VirtualHandle_virtualCall:1071isVirtual = true;1072case TR::java_lang_invoke_DirectHandle_directCall:1073{1074TR_J9VMBase *fej9 = comp()->fej9();1075TR_J9VMBase::MethodOfHandle moh = fej9->methodOfDirectOrVirtualHandle(1076_calltarget->_calleeMethod->getMethodHandleLocation(), isVirtual);10771078TR_ASSERT_FATAL(moh.j9method != NULL, "Must have a j9method to generate a custom call");1079uint32_t vTableSlot = isVirtual ? (uint32_t)moh.vmSlot : 0;1080TR_ResolvedMethod *newCallee = fej9->createResolvedMethodWithVTableSlot(1081trMemory(), vTableSlot, moh.j9method, _calltarget->_calleeMethod);10821083// Don't refine virtualCall to an interface method, which will confuse1084// the virtual call site logic in visitInvokestatic()1085TR_OpaqueClassBlock *defClass = newCallee->classOfMethod();1086if (isVirtual && TR::Compiler->cls.isInterfaceClass(comp(), defClass))1087return;10881089isIndirectCall = isVirtual;1090callee = newCallee;1091return;1092}1093#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)1094case TR::java_lang_invoke_MethodHandle_linkToStatic:1095case TR::java_lang_invoke_MethodHandle_linkToSpecial:1096case TR::java_lang_invoke_MethodHandle_linkToVirtual:1097{1098TR::KnownObjectTable::Index memberNameIndex = top()->getKnownObjectIndex();1099TR_J9VMBase* fej9 = comp()->fej9();1100auto targetMethod = fej9->targetMethodFromMemberName(comp(), memberNameIndex);1101if (!targetMethod)1102return;11031104uint32_t vTableSlot = 0;1105if (rm == TR::java_lang_invoke_MethodHandle_linkToVirtual)1106{1107uintptr_t slot = fej9->vTableOrITableIndexFromMemberName(comp(), memberNameIndex);1108if ((slot & J9_JNI_MID_INTERFACE) == 0)1109{1110vTableSlot = (uint32_t)slot;1111}1112else1113{1114// TODO: Refine to the method identified by the itable slot1115// together with the defining (interface) class of the method1116// from the MemberName. For such a refinement to matter,1117// TR_J9InterfaceCallSite will need to be able to find call1118// targets without a CP index.1119//1120// For the moment, just leave the call unrefined.1121//1122return;1123}1124}11251126// Direct or virtual dispatch. A vTableSlot of 0 indicates a direct1127// call, in which case vTableSlot won't really be used as such.1128callee = fej9->createResolvedMethodWithVTableSlot(comp()->trMemory(), vTableSlot, targetMethod, _calltarget->_calleeMethod);11291130isIndirectCall = vTableSlot != 0;1131TR_ASSERT_FATAL(1132!isIndirectCall1133|| rm == TR::java_lang_invoke_MethodHandle_linkToVirtual1134|| rm == TR::java_lang_invoke_MethodHandle_linkToInterface,1135"indirect linkTo call should only be linkToVirtual or linkToInterface");11361137heuristicTrace(tracer(), "Refine linkTo to %s\n", callee->signature(trMemory(), stackAlloc));1138// The refined method doesn't take MemberName as an argument, pop MemberName out of the operand stack1139pop();1140return;1141}1142#endif //J9VM_OPT_OPENJDK_METHODHANDLE11431144default:1145break;1146}1147}11481149bool1150InterpreterEmulator::findAndCreateCallsitesFromBytecodes(bool wasPeekingSuccessfull, bool withState)1151{1152heuristicTrace(tracer(),"Find and create callsite %s\n", withState ? "with state" : "without state");11531154if (withState)1155initializeIteratorWithState();1156_wasPeekingSuccessfull = wasPeekingSuccessfull;1157_currentInlinedBlock = NULL;1158TR_J9ByteCode bc = first();1159while (bc != J9BCunknown)1160{1161heuristicTrace(tracer(), "%4d: %s\n", _bcIndex, comp()->fej9()->getByteCodeName(_code[_bcIndex]));11621163_currentCallSite = NULL;1164_currentCallMethod = NULL;1165_currentCallMethodUnrefined = NULL;11661167if (_InterpreterEmulatorFlags[_bcIndex].testAny(InterpreterEmulator::BytecodePropertyFlag::bbStart))1168{1169_currentInlinedBlock = TR_J9EstimateCodeSize::getBlock(comp(), _blocks, _calltarget->_calleeMethod, _bcIndex, *_cfg);1170debugTrace(tracer(),"Found current block %p, number %d for bci %d\n", _currentInlinedBlock, (_currentInlinedBlock) ? _currentInlinedBlock->getNumber() : -1, _bcIndex);1171}117211731174TR_ASSERT_FATAL(!isGenerated(_bcIndex), "InterpreterEmulator::findCallsitesFromBytecodes bcIndex %d has been generated\n", _bcIndex);1175_newBCInfo->setByteCodeIndex(_bcIndex);11761177switch (bc)1178{1179case J9BCinvokedynamic: visitInvokedynamic(); break;1180case J9BCinvokevirtual: visitInvokevirtual(); break;1181#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)1182case J9BCinvokehandle: visitInvokehandle(); break;1183#endif1184case J9BCinvokespecial:1185case J9BCinvokespecialsplit: visitInvokespecial(); break;1186case J9BCinvokestatic:1187case J9BCinvokestaticsplit: visitInvokestatic(); break;1188case J9BCinvokeinterface: visitInvokeinterface(); break;11891190default:1191break;1192}11931194if (_iteratorWithState)1195{1196if (maintainStack(bc))1197dumpStack();1198else1199return false;1200}12011202_pca.updateArg(bc);1203bc = findNextByteCodeToVisit();1204}12051206heuristicTrace(tracer(), "Finish findAndCreateCallsitesFromBytecodes\n");1207return true;1208}12091210TR_J9ByteCode1211InterpreterEmulator::findNextByteCodeToVisit()1212{1213if (!_iteratorWithState)1214next();1215else1216{1217setIsGenerated(_bcIndex);1218if (_InterpreterEmulatorFlags[_bcIndex].testAny(InterpreterEmulator::BytecodePropertyFlag::isBranch))1219{1220setIndex(Base::findNextByteCodeToGen());1221debugTrace(tracer(), "current bc is branch next bytecode to generate is %d\n", _bcIndex);1222}1223else next();1224}12251226if (_bcIndex < _maxByteCodeIndex && _InterpreterEmulatorFlags[_bcIndex].testAny(InterpreterEmulator::BytecodePropertyFlag::bbStart))1227{1228if (isGenerated(_bcIndex))1229setIndex(Base::findNextByteCodeToGen());1230}1231return current();1232}12331234void1235InterpreterEmulator::prepareToFindAndCreateCallsites(TR::Block **blocks, flags8_t * flags, TR_CallSite ** callSites, TR::CFG *cfg, TR_ByteCodeInfo *newBCInfo, int32_t recursionDepth, TR_CallStack *callStack)1236{1237_blocks = blocks;1238_InterpreterEmulatorFlags = flags;1239_callSites = callSites;1240_cfg = cfg;1241_newBCInfo = newBCInfo;1242_recursionDepth = recursionDepth;1243_callStack = callStack;1244_nonColdCallExists = false;1245_inlineableCallExists = false;1246}12471248void1249InterpreterEmulator::visitInvokedynamic()1250{1251TR_ResolvedJ9Method * owningMethod = static_cast<TR_ResolvedJ9Method*>(_methodSymbol->getResolvedMethod());1252int32_t callSiteIndex = next2Bytes();1253#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)1254if (owningMethod->isUnresolvedCallSiteTableEntry(callSiteIndex)1255|| comp()->compileRelocatableCode()1256) return; // do nothing if unresolved, is AOT compilation1257uintptr_t * invokeCacheArray = (uintptr_t *) owningMethod->callSiteTableEntryAddress(callSiteIndex);1258updateKnotAndCreateCallSiteUsingInvokeCacheArray(owningMethod, invokeCacheArray, -1);1259#else1260bool isInterface = false;1261bool isIndirectCall = false;1262TR::Method *interfaceMethod = 0;1263TR::TreeTop *callNodeTreeTop = 0;1264TR::Node *parent = 0;1265TR::Node *callNode = 0;1266TR::ResolvedMethodSymbol *resolvedSymbol = 0;1267Operand *result = NULL;1268TR::KnownObjectTable *knot = comp()->getOrCreateKnownObjectTable();1269if (knot && !owningMethod->isUnresolvedCallSiteTableEntry(callSiteIndex))1270{1271isIndirectCall = true;1272uintptr_t *entryLocation = (uintptr_t*)owningMethod->callSiteTableEntryAddress(callSiteIndex);1273// Add callsite handle to known object table1274knot->getOrCreateIndexAt((uintptr_t*)entryLocation);1275_currentCallMethod = comp()->fej9()->createMethodHandleArchetypeSpecimen(this->trMemory(), entryLocation, owningMethod);1276_currentCallMethodUnrefined = _currentCallMethod;1277bool allconsts= false;12781279heuristicTrace(tracer(),"numberOfExplicitParameters = %d _pca.getNumPrevConstArgs = %d\n", _currentCallMethod->numberOfExplicitParameters() , _pca.getNumPrevConstArgs(_currentCallMethod->numberOfExplicitParameters()));1280if (_currentCallMethod->numberOfExplicitParameters() > 0 && _currentCallMethod->numberOfExplicitParameters() <= _pca.getNumPrevConstArgs(_currentCallMethod->numberOfExplicitParameters()))1281allconsts = true;12821283TR_CallSite *callsite = new (comp()->trHeapMemory()) TR_J9MethodHandleCallSite(_calltarget->_calleeMethod, callNodeTreeTop, parent,1284callNode, interfaceMethod, _currentCallMethod->classOfMethod(),1285-1, -1, _currentCallMethod,1286resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo, comp(),1287_recursionDepth, allconsts);12881289findTargetAndUpdateInfoForCallsite(callsite);1290}1291#endif //J9VM_OPT_OPENJDK_METHODHANDLE1292}12931294#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)1295void1296InterpreterEmulator::visitInvokehandle()1297{1298int32_t cpIndex = next2Bytes();1299TR_ResolvedJ9Method * owningMethod = static_cast<TR_ResolvedJ9Method*>(_methodSymbol->getResolvedMethod());1300if (owningMethod->isUnresolvedMethodTypeTableEntry(cpIndex)1301|| comp()->compileRelocatableCode()1302) return; // do nothing if unresolved, is an AOT compilation1303uintptr_t * invokeCacheArray = (uintptr_t *) owningMethod->methodTypeTableEntryAddress(cpIndex);1304updateKnotAndCreateCallSiteUsingInvokeCacheArray(owningMethod, invokeCacheArray, cpIndex);1305}13061307void1308InterpreterEmulator::updateKnotAndCreateCallSiteUsingInvokeCacheArray(TR_ResolvedJ9Method* owningMethod, uintptr_t * invokeCacheArray, int32_t cpIndex)1309{1310TR_J9VMBase *fej9 = comp()->fej9();1311TR::KnownObjectTable::Index idx = fej9->getKnotIndexOfInvokeCacheArrayAppendixElement(comp(), invokeCacheArray);1312if (_iteratorWithState)1313{1314if (idx != TR::KnownObjectTable::UNKNOWN)1315push(new (trStackMemory()) KnownObjOperand(idx));1316else1317pushUnknownOperand();1318}13191320TR_ResolvedMethod * targetMethod = fej9->targetMethodFromInvokeCacheArrayMemberNameObj(comp(), owningMethod, invokeCacheArray);1321bool isInterface = false;1322bool isIndirectCall = false;1323TR::Method *interfaceMethod = 0;1324TR::TreeTop *callNodeTreeTop = 0;1325TR::Node *parent = 0;1326TR::Node *callNode = 0;1327TR::ResolvedMethodSymbol *resolvedSymbol = 0;1328TR::KnownObjectTable *knot = comp()->getOrCreateKnownObjectTable();1329bool allconsts = false;1330if (targetMethod->numberOfExplicitParameters() > 0 && targetMethod->numberOfExplicitParameters() <= _pca.getNumPrevConstArgs(targetMethod->numberOfExplicitParameters()))1331allconsts = true;1332TR_CallSite *callsite = new (comp()->trHeapMemory()) TR_DirectCallSite(_calltarget->_calleeMethod, callNodeTreeTop, parent,1333callNode, interfaceMethod, targetMethod->classOfMethod(),1334-1, cpIndex, targetMethod,1335resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo, comp(),1336_recursionDepth, allconsts);13371338findTargetAndUpdateInfoForCallsite(callsite, idx);1339}13401341#endif //J9VM_OPT_OPENJDK_METHODHANDLE13421343bool1344InterpreterEmulator::isCurrentCallUnresolvedOrCold(TR_ResolvedMethod *resolvedMethod, bool isUnresolvedInCP)1345{1346if (!resolvedMethod)1347return true;13481349bool isIndirectCall = false;1350if (current() == J9BCinvokevirtual)1351isIndirectCall = true;13521353// Since bytecodes in a thunk archetype are never interpreted,1354// most of the cp entries may appear unresolved, and we always1355// compile-time resolve the cp entries. Thus ignore resolution1356// status of cp entries of thunk arthetype1357//1358if (_callerIsThunkArchetype)1359return resolvedMethod->isCold(comp(), isIndirectCall);1360else1361return (isUnresolvedInCP || resolvedMethod->isCold(comp(), isIndirectCall));1362}13631364void1365InterpreterEmulator::debugUnresolvedOrCold(TR_ResolvedMethod *resolvedMethod)1366{1367int32_t cpIndex = next2Bytes();1368if(tracer()->heuristicLevel())1369{1370if (resolvedMethod)1371heuristicTrace(tracer(), "Depth %d: Call at bc index %d is Cold. Not searching for targets. Signature %s", _recursionDepth, _bcIndex, resolvedMethod->signature(comp()->trMemory()));1372else1373{1374switch (current())1375{1376case J9BCinvokespecialsplit:1377cpIndex |= J9_SPECIAL_SPLIT_TABLE_INDEX_FLAG;1378break;1379case J9BCinvokestaticsplit:1380cpIndex |= J9_STATIC_SPLIT_TABLE_INDEX_FLAG;1381break;13821383default:1384break;1385}1386TR::Method *meth = comp()->fej9()->createMethod(this->trMemory(), _calltarget->_calleeMethod->containingClass(), cpIndex);1387heuristicTrace(tracer(), "Depth %d: Call at bc index %d is Cold. Not searching for targets. Signature %s", _recursionDepth, _bcIndex, meth->signature(comp()->trMemory()));1388}1389}1390}13911392void1393InterpreterEmulator::refineResolvedCalleeForInvokevirtual(TR_ResolvedMethod *&callee, bool &isIndirectCall)1394{1395TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");1396if (!comp()->getOrCreateKnownObjectTable())1397return;13981399TR::RecognizedMethod rm = callee->getRecognizedMethod();1400switch (rm)1401{1402#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)1403case TR::java_lang_invoke_MethodHandle_invokeBasic:1404{1405int argNum = callee->numberOfExplicitParameters();1406TR::KnownObjectTable::Index receiverIndex = topn(argNum)->getKnownObjectIndex();1407TR_J9VMBase* fej9 = comp()->fej9();1408auto targetMethod = fej9->targetMethodFromMethodHandle(comp(), receiverIndex);1409if (!targetMethod) return;14101411isIndirectCall = false;1412callee = fej9->createResolvedMethod(comp()->trMemory(), targetMethod, callee->owningMethod());1413heuristicTrace(tracer(), "Refine invokeBasic to %s\n", callee->signature(trMemory(), stackAlloc));1414return;1415}1416#endif //J9VM_OPT_OPENJDK_METHODHANDLE1417default:1418return;1419}1420}14211422void1423InterpreterEmulator::visitInvokevirtual()1424{1425int32_t cpIndex = next2Bytes();1426auto calleeMethod = (TR_ResolvedJ9Method*)_calltarget->_calleeMethod;1427bool isUnresolvedInCP;1428// Calls in thunk archetype won't be executed by interpreter, so they may appear as unresolved1429bool ignoreRtResolve = _callerIsThunkArchetype;1430_currentCallMethod = calleeMethod->getResolvedPossiblyPrivateVirtualMethod(comp(), cpIndex, ignoreRtResolve, &isUnresolvedInCP);1431_currentCallMethodUnrefined = _currentCallMethod;1432Operand *result = NULL;1433if (isCurrentCallUnresolvedOrCold(_currentCallMethod, isUnresolvedInCP))1434{1435debugUnresolvedOrCold(_currentCallMethod);1436}1437else if (_currentCallMethod)1438{1439bool isIndirectCall = !_currentCallMethod->isFinal() && !_currentCallMethod->isPrivate();1440if (_iteratorWithState)1441refineResolvedCalleeForInvokevirtual(_currentCallMethod, isIndirectCall);14421443// Customization logic is not needed in customized thunk or in inlining1444// with known MethodHandle object1445// Since branch folding is disabled and we're ignoring the coldness info1446// in thunk archetype, calls to the following method will be added to the1447// call site list and take up some inlining budget, causing less methods1448// to be inlined. Don't create call site for them1449//1450switch (_currentCallMethod->getRecognizedMethod())1451{1452case TR::java_lang_invoke_MethodHandle_doCustomizationLogic:1453case TR::java_lang_invoke_MethodHandle_undoCustomizationLogic:1454if (_callerIsThunkArchetype)1455return;14561457default:1458break;1459}14601461bool allconsts= false;1462heuristicTrace(tracer(),"numberOfExplicitParameters = %d _pca.getNumPrevConstArgs = %d\n",_currentCallMethod->numberOfExplicitParameters() ,_pca.getNumPrevConstArgs(_currentCallMethod->numberOfExplicitParameters()));1463if ( _currentCallMethod->numberOfExplicitParameters() > 0 && _currentCallMethod->numberOfExplicitParameters() <= _pca.getNumPrevConstArgs(_currentCallMethod->numberOfExplicitParameters()))1464allconsts = true;14651466TR_CallSite *callsite;1467bool isInterface = false;1468TR::Method *interfaceMethod = 0;1469TR::TreeTop *callNodeTreeTop = 0;1470TR::Node *parent = 0;1471TR::Node *callNode = 0;1472TR::ResolvedMethodSymbol *resolvedSymbol = 0;14731474Operand *receiver = NULL;1475if (_iteratorWithState)1476receiver = topn(_currentCallMethodUnrefined->numberOfExplicitParameters());14771478if (_currentCallMethod->convertToMethod()->isArchetypeSpecimen() && _currentCallMethod->getMethodHandleLocation())1479{1480callsite = new (comp()->trHeapMemory()) TR_J9MethodHandleCallSite(_calltarget->_calleeMethod, callNodeTreeTop, parent,1481callNode, interfaceMethod, _currentCallMethod->classOfMethod(),1482-1, cpIndex, _currentCallMethod,1483resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo, comp(),1484_recursionDepth, allconsts);1485}1486else if (_currentCallMethod->getRecognizedMethod() == TR::java_lang_invoke_MethodHandle_invokeExact1487|| (_currentCallMethod->getRecognizedMethod() == TR::java_lang_invoke_MethodHandle_invokeBasic1488&& receiver != NULL && receiver->asMutableCallsiteTargetOperand() != NULL))1489{1490TR_J9MutableCallSite *inlinerMcs = new (comp()->trHeapMemory()) TR_J9MutableCallSite(_calltarget->_calleeMethod, callNodeTreeTop, parent,1491callNode, interfaceMethod, _currentCallMethod->classOfMethod(),1492(int32_t) _currentCallMethod->virtualCallSelector(cpIndex), cpIndex, _currentCallMethod,1493resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo, comp(),1494_recursionDepth, allconsts);1495if (_currentCallMethod->getRecognizedMethod() == TR::java_lang_invoke_MethodHandle_invokeBasic)1496{1497// Set the MCS reference location so that TR_J9MutableCallSite1498// doesn't go rummaging through the trees (with1499// isMutableCallSiteTargetInvokeExact()) looking for1500// mcs.target.invokeExact() or mcs.getTarget().invokeExact(). Those1501// patterns won't be found:1502// - the final call is invokeBasic(), not invokeExact()1503// - rather than a load or getTarget() call, the target will come1504// from Invokers.getCallSiteTarget() (or, once inlining works for1505// dynamic invoker handles, another invokeBasic())1506//1507// But there's no need to look through the trees anyway, since the1508// MCS is already known at this point.15091510TR::KnownObjectTable *knot = comp()->getOrCreateKnownObjectTable();1511MutableCallsiteTargetOperand *mcsOperand = receiver->asMutableCallsiteTargetOperand();1512TR::KnownObjectTable::Index mcsIndex = mcsOperand->getMutableCallsiteIndex();1513inlinerMcs->setMCSReferenceLocation(knot->getPointerLocation(mcsIndex));1514}15151516callsite = inlinerMcs;1517}1518else if (isIndirectCall)1519{1520callsite = new (comp()->trHeapMemory()) TR_J9VirtualCallSite(_calltarget->_calleeMethod, callNodeTreeTop, parent,1521callNode, interfaceMethod, _currentCallMethod->classOfMethod(),1522(int32_t) _currentCallMethod->virtualCallSelector(cpIndex), cpIndex, _currentCallMethod,1523resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo, comp(),1524_recursionDepth, allconsts);15251526}1527else1528{1529callsite = new (comp()->trHeapMemory()) TR_DirectCallSite(_calltarget->_calleeMethod, callNodeTreeTop, parent,1530callNode, interfaceMethod, _currentCallMethod->classOfMethod(),1531-1, cpIndex, _currentCallMethod,1532resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo, comp(),1533_recursionDepth, allconsts);15341535}15361537if(tracer()->debugLevel())1538_pca.printIndexes(comp());1539findTargetAndUpdateInfoForCallsite(callsite);1540}15411542}15431544void1545InterpreterEmulator::visitInvokespecial()1546{1547int32_t cpIndex = next2Bytes();1548bool isUnresolvedInCP;1549_currentCallMethod = _calltarget->_calleeMethod->getResolvedSpecialMethod(comp(), (current() == J9BCinvokespecialsplit)?cpIndex |= J9_SPECIAL_SPLIT_TABLE_INDEX_FLAG:cpIndex, &isUnresolvedInCP);1550_currentCallMethodUnrefined = _currentCallMethod;1551if (isCurrentCallUnresolvedOrCold(_currentCallMethod, isUnresolvedInCP))1552{1553debugUnresolvedOrCold(_currentCallMethod);1554}1555else1556{1557bool allconsts= false;1558heuristicTrace(tracer(),"numberOfExplicitParameters = %d _pca.getNumPrevConstArgs = %d\n",_currentCallMethod->numberOfExplicitParameters() ,_pca.getNumPrevConstArgs(_currentCallMethod->numberOfExplicitParameters()));1559if (_currentCallMethod->numberOfExplicitParameters() > 0 && _currentCallMethod->numberOfExplicitParameters() <= _pca.getNumPrevConstArgs(_currentCallMethod->numberOfExplicitParameters()))1560allconsts = true;15611562bool isIndirectCall = false;1563bool isInterface = false;1564TR::Method *interfaceMethod = 0;1565TR::TreeTop *callNodeTreeTop = 0;1566TR::Node *parent = 0;1567TR::Node *callNode = 0;1568TR::ResolvedMethodSymbol *resolvedSymbol = 0;1569TR_CallSite *callsite = new (comp()->trHeapMemory()) TR_DirectCallSite(_calltarget->_calleeMethod, callNodeTreeTop, parent,1570callNode, interfaceMethod, _currentCallMethod->classOfMethod(), -1, cpIndex,1571_currentCallMethod, resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo, comp(),1572_recursionDepth, allconsts);1573findTargetAndUpdateInfoForCallsite(callsite);1574}1575}15761577void1578InterpreterEmulator::visitInvokestatic()1579{1580int32_t cpIndex = next2Bytes();1581bool isUnresolvedInCP;1582_currentCallMethod = _calltarget->_calleeMethod->getResolvedStaticMethod(comp(), (current() == J9BCinvokestaticsplit) ? cpIndex |= J9_STATIC_SPLIT_TABLE_INDEX_FLAG:cpIndex, &isUnresolvedInCP);1583_currentCallMethodUnrefined = _currentCallMethod;1584if (isCurrentCallUnresolvedOrCold(_currentCallMethod, isUnresolvedInCP))1585{1586debugUnresolvedOrCold(_currentCallMethod);1587}1588else1589{1590bool allconsts= false;15911592heuristicTrace(tracer(),"numberOfExplicitParameters = %d _pca.getNumPrevConstArgs = %d\n",_currentCallMethod->numberOfExplicitParameters() ,_pca.getNumPrevConstArgs(_currentCallMethod->numberOfExplicitParameters()));1593if (_currentCallMethod->numberOfExplicitParameters() > 0 && _currentCallMethod->numberOfExplicitParameters() <= _pca.getNumPrevConstArgs(_currentCallMethod->numberOfExplicitParameters()))1594allconsts = true;15951596TR::KnownObjectTable::Index mhIndex = TR::KnownObjectTable::UNKNOWN;1597TR::KnownObjectTable::Index mcsIndex = TR::KnownObjectTable::UNKNOWN;1598bool isIndirectCall = false;1599if (_iteratorWithState)1600refineResolvedCalleeForInvokestatic(_currentCallMethod, mcsIndex, mhIndex, isIndirectCall);16011602bool isInterface = false;1603TR_CallSite *callsite = NULL;1604TR::Method *interfaceMethod = 0;1605TR::TreeTop *callNodeTreeTop = 0;1606TR::Node *parent = 0;1607TR::Node *callNode = 0;1608TR::ResolvedMethodSymbol *resolvedSymbol = 0;16091610if (_currentCallMethod->convertToMethod()->isArchetypeSpecimen() &&1611_currentCallMethod->getMethodHandleLocation() &&1612mcsIndex == TR::KnownObjectTable::UNKNOWN)1613{1614callsite = new (comp()->trHeapMemory()) TR_J9MethodHandleCallSite( _calltarget->_calleeMethod, callNodeTreeTop, parent,1615callNode, interfaceMethod, _currentCallMethod->classOfMethod(),1616-1, cpIndex, _currentCallMethod,1617resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo, comp(),1618_recursionDepth, allconsts);1619}1620else if (_currentCallMethod->convertToMethod()->isArchetypeSpecimen() &&1621_currentCallMethod->getMethodHandleLocation() &&1622mcsIndex != TR::KnownObjectTable::UNKNOWN)1623{1624TR_J9MutableCallSite *mcs = new (comp()->trHeapMemory()) TR_J9MutableCallSite( _calltarget->_calleeMethod, callNodeTreeTop, parent,1625callNode, interfaceMethod, _currentCallMethod->classOfMethod(),1626(int32_t) _currentCallMethod->virtualCallSelector(cpIndex), cpIndex, _currentCallMethod,1627resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo, comp(),1628_recursionDepth, allconsts);1629if (mcsIndex != TR::KnownObjectTable::UNKNOWN)1630{1631if (comp()->getKnownObjectTable())1632mcs->setMCSReferenceLocation(comp()->getKnownObjectTable()->getPointerLocation(mcsIndex));1633}1634callsite = mcs;1635}1636else if (isIndirectCall)1637{1638int32_t noCPIndex = -1; // The method is not referenced via the constant pool1639callsite = new (comp()->trHeapMemory()) TR_J9VirtualCallSite(1640_calltarget->_calleeMethod, callNodeTreeTop, parent, callNode,1641interfaceMethod, _currentCallMethod->classOfMethod(), (int32_t) _currentCallMethod->virtualCallSelector(cpIndex), noCPIndex,1642_currentCallMethod, resolvedSymbol, isIndirectCall, isInterface,1643*_newBCInfo, comp(), _recursionDepth, allconsts);1644}1645else1646{1647callsite = new (comp()->trHeapMemory()) TR_DirectCallSite(_calltarget->_calleeMethod, callNodeTreeTop, parent, callNode, interfaceMethod,1648_currentCallMethod->classOfMethod(), -1, cpIndex, _currentCallMethod, resolvedSymbol,1649isIndirectCall, isInterface, *_newBCInfo, comp(),1650_recursionDepth, allconsts);1651}1652findTargetAndUpdateInfoForCallsite(callsite);1653}16541655}16561657void1658InterpreterEmulator::visitInvokeinterface()1659{1660int32_t cpIndex = next2Bytes();1661auto calleeMethod = (TR_ResolvedJ9Method*)_calltarget->_calleeMethod;1662_currentCallMethod = calleeMethod->getResolvedImproperInterfaceMethod(comp(), cpIndex);1663_currentCallMethodUnrefined = _currentCallMethod;1664bool isIndirectCall = true;1665bool isInterface = true;1666if (_currentCallMethod)1667{1668isInterface = false;1669isIndirectCall = !_currentCallMethod->isPrivate() &&1670!_currentCallMethod->convertToMethod()->isFinalInObject();1671}16721673TR::Method * interfaceMethod = NULL;1674if (isInterface)1675interfaceMethod = comp()->fej9()->createMethod(this->trMemory(), _calltarget->_calleeMethod->containingClass(), cpIndex);16761677TR::TreeTop *callNodeTreeTop = 0;1678TR::Node *parent = 0;1679TR::Node *callNode = 0;1680TR::ResolvedMethodSymbol *resolvedSymbol = 0;16811682uint32_t explicitParams = 0;1683if (isInterface)1684explicitParams = interfaceMethod->numberOfExplicitParameters();1685else1686explicitParams = _currentCallMethod->numberOfExplicitParameters();16871688bool allconsts= false;1689heuristicTrace(tracer(), "numberOfExplicitParameters = %d _pca.getNumPrevConstArgs = %d\n", explicitParams, _pca.getNumPrevConstArgs(explicitParams));1690if (explicitParams > 0 && explicitParams <= _pca.getNumPrevConstArgs(explicitParams))1691allconsts = true;16921693TR_CallSite *callsite = NULL;1694if (isInterface)1695{1696TR_OpaqueClassBlock * thisClass = NULL;1697callsite = new (comp()->trHeapMemory()) TR_J9InterfaceCallSite(1698_calltarget->_calleeMethod, callNodeTreeTop, parent, callNode,1699interfaceMethod, thisClass, -1, cpIndex, _currentCallMethod,1700resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo,1701comp(), _recursionDepth, allconsts);1702}1703else if (isIndirectCall)1704{1705callsite = new (comp()->trHeapMemory()) TR_J9VirtualCallSite(1706_calltarget->_calleeMethod, callNodeTreeTop, parent, callNode,1707interfaceMethod, _currentCallMethod->classOfMethod(), (int32_t) _currentCallMethod->virtualCallSelector(cpIndex), cpIndex,1708_currentCallMethod, resolvedSymbol, isIndirectCall, isInterface,1709*_newBCInfo, comp(), _recursionDepth, allconsts);1710}1711else1712{1713callsite = new (comp()->trHeapMemory()) TR_DirectCallSite(1714_calltarget->_calleeMethod, callNodeTreeTop, parent, callNode,1715interfaceMethod, _currentCallMethod->classOfMethod(), -1, cpIndex,1716_currentCallMethod, resolvedSymbol, isIndirectCall, isInterface,1717*_newBCInfo, comp(), _recursionDepth, allconsts);1718}17191720if(tracer()->debugLevel())1721{1722_pca.printIndexes(comp());1723}1724findTargetAndUpdateInfoForCallsite(callsite);1725}17261727Operand*1728InterpreterEmulator::createOperandFromPrexArg(TR_PrexArgument* prexArgument)1729{1730auto prexKnowledge = TR_PrexArgument::knowledgeLevel(prexArgument);1731switch (prexKnowledge)1732{1733case KNOWN_OBJECT:1734return new (trStackMemory()) KnownObjOperand(prexArgument->getKnownObjectIndex(), prexArgument->getClass());1735case FIXED_CLASS:1736return new (trStackMemory()) FixedClassOperand(prexArgument->getClass());1737case PREEXISTENT:1738return new (trStackMemory()) PreexistentObjectOperand(prexArgument->getClass());1739case NONE:1740return prexArgument->getClass() ? new (trStackMemory()) ObjectOperand(prexArgument->getClass()) : NULL;1741}1742return NULL;1743}17441745TR_PrexArgument*1746InterpreterEmulator::createPrexArgFromOperand(Operand* operand)1747{1748if (operand->asKnownObject())1749{1750auto koi = operand->getKnownObjectIndex();1751auto knot = comp()->getOrCreateKnownObjectTable();1752if (knot && !knot->isNull(koi))1753return new (comp()->trHeapMemory()) TR_PrexArgument(operand->getKnownObjectIndex(), comp());1754}1755else if (operand->asObjectOperand() && operand->asObjectOperand()->getClass())1756{1757TR_OpaqueClassBlock* clazz = operand->asObjectOperand()->getClass();1758TR_PrexArgument::ClassKind kind = TR_PrexArgument::ClassIsUnknown;1759if (operand->asFixedClassOperand())1760kind = TR_PrexArgument::ClassIsFixed;1761else if (operand->asPreexistentObjectOperand())1762kind = TR_PrexArgument::ClassIsPreexistent;17631764return new (comp()->trHeapMemory()) TR_PrexArgument(kind, clazz);1765}17661767return NULL;1768}17691770TR_PrexArgInfo*1771InterpreterEmulator::computePrexInfo(1772TR_CallSite *callsite, TR::KnownObjectTable::Index appendix)1773{1774if (tracer()->heuristicLevel())1775_ecs->getInliner()->tracer()->dumpCallSite(callsite, "Compute prex info for call site %p\n", callsite);17761777int32_t numOfArgs = 0;1778if (callsite->_isInterface)1779{1780numOfArgs = callsite->_interfaceMethod->numberOfExplicitParameters() + 1;1781}1782else if (callsite->_initialCalleeMethod)1783{1784numOfArgs = callsite->_initialCalleeMethod->numberOfParameters();1785}17861787if (numOfArgs == 0)1788return NULL;17891790// Always favor prex arg from operand if we're iterating with state1791// But not for thunk archetype as the method's bytecodes manipulate1792// the operand stack differently, and one int `argPlacehowler`1793// argument can represent more than one arguments1794//1795if (!_callerIsThunkArchetype && _iteratorWithState)1796{1797TR_PrexArgInfo* prexArgInfo = new (comp()->trHeapMemory()) TR_PrexArgInfo(numOfArgs, comp()->trMemory());1798for (int32_t i = 0; i < numOfArgs; i++)1799{1800int32_t posInStack = numOfArgs - i - 1;1801prexArgInfo->set(i, createPrexArgFromOperand(topn(posInStack)));1802}18031804if (tracer()->heuristicLevel())1805{1806alwaysTrace(tracer(), "argInfo from operand stack:");1807prexArgInfo->dumpTrace();1808}1809return prexArgInfo;1810}1811else if (_wasPeekingSuccessfull)1812{1813auto callNodeTT = TR_PrexArgInfo::getCallTree(_methodSymbol, callsite, tracer());1814if (callNodeTT)1815{1816// Temporarily set call tree and call node of callsite such that computePrexInfo can use it1817callsite->_callNodeTreeTop = callNodeTT;1818callsite->_callNode = callNodeTT->getNode()->getChild(0);1819auto prexArgInfo = TR_J9InlinerUtil::computePrexInfo(_ecs->getInliner(), callsite, _calltarget->_ecsPrexArgInfo);18201821// Reset call tree and call node1822callsite->_callNodeTreeTop = NULL;1823callsite->_callNode = NULL;1824return prexArgInfo;1825}1826}1827#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)1828else if (appendix != TR::KnownObjectTable::UNKNOWN)1829{1830TR_ASSERT_FATAL(!callsite->isIndirectCall(), "appendix with indirect call");1831TR_ASSERT_FATAL(1832comp()->fej9()->isLambdaFormGeneratedMethod(callsite->_initialCalleeMethod),1833"appendix with non-LambdaForm method - expected a call site adapter");18341835TR::KnownObjectTable *knot = comp()->getKnownObjectTable();1836if (!knot->isNull(appendix))1837{1838TR_PrexArgInfo* prexArgInfo =1839new (comp()->trHeapMemory()) TR_PrexArgInfo(numOfArgs, comp()->trMemory());18401841auto arg = new (comp()->trHeapMemory()) TR_PrexArgument(appendix, comp());1842prexArgInfo->set(numOfArgs - 1, arg);18431844if (tracer()->heuristicLevel())1845{1846alwaysTrace(tracer(), "argInfo from appendix object:");1847prexArgInfo->dumpTrace();1848}18491850return prexArgInfo;1851}1852}1853#endif18541855return NULL;1856}18571858void1859InterpreterEmulator::findTargetAndUpdateInfoForCallsite(1860TR_CallSite *callsite, TR::KnownObjectTable::Index appendix)1861{1862_currentCallSite = callsite;1863callsite->_callerBlock = _currentInlinedBlock;1864callsite->_ecsPrexArgInfo = computePrexInfo(callsite, appendix);18651866if (_ecs->isInlineable(_callStack, callsite))1867{1868_callSites[_bcIndex] = callsite;1869_inlineableCallExists = true;18701871if (!_currentInlinedBlock->isCold())1872_nonColdCallExists = true;18731874for (int i = 0; i < callsite->numTargets(); i++)1875callsite->getTarget(i)->_originatingBlock = _currentInlinedBlock;1876}1877else1878{1879//support counters1880_calltarget->addDeadCallee(callsite);1881}1882}188318841885