Path: blob/master/runtime/compiler/ilgen/IlGenerator.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2000, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "codegen/CodeGenerator.hpp"23#include "compile/InlineBlock.hpp"24#include "compile/Method.hpp"25#include "compile/ResolvedMethod.hpp"26#include "control/Recompilation.hpp"27#include "control/RecompilationInfo.hpp"28#include "env/PersistentCHTable.hpp"29#include "env/CompilerEnv.hpp"30#include "il/Node.hpp"31#include "il/Node_inlines.hpp"32#include "il/ParameterSymbol.hpp"33#include "il/TreeTop.hpp"34#include "il/TreeTop_inlines.hpp"35#include "ilgen/IlGeneratorMethodDetails_inlines.hpp"36#include "infra/Cfg.hpp"37#include "infra/Checklist.hpp"38#include "env/VMJ9.h"39#include "ilgen/J9ByteCodeIlGenerator.hpp"40#include "optimizer/BoolArrayStoreTransformer.hpp"41#include "ras/DebugCounter.hpp"42#include "optimizer/TransformUtil.hpp"43#include "env/JSR292Methods.h"4445#define OPT_DETAILS "O^O ILGEN: "4647TR_J9ByteCodeIlGenerator::TR_J9ByteCodeIlGenerator(48TR::IlGeneratorMethodDetails & methodDetails, TR::ResolvedMethodSymbol * methodSymbol, TR_J9VMBase * fe, TR::Compilation * comp,49TR::SymbolReferenceTable * symRefTab, bool forceClassLookahead, TR_InlineBlocks *blocksToInline, int32_t argPlaceholderSlot) //TR_ScratchList<TR_InlineBlock> *blocksToInline)50: TR_J9ByteCodeIteratorWithState(methodSymbol, fe, comp),51_methodDetails(methodDetails),52_symRefTab(symRefTab),53_classLookaheadSymRefTab(NULL),54_blockAddedVisitCount(comp->incVisitCount()),55_generateWriteBarriersForGC(TR::Compiler->om.writeBarrierType() != gc_modron_wrtbar_none),56_generateWriteBarriersForFieldWatch(comp->getOption(TR_EnableFieldWatch)),57_generateReadBarriersForFieldWatch(comp->getOption(TR_EnableFieldWatch)),58_suppressSpineChecks(false),59_implicitMonitorExits(comp->trMemory()),60_finalizeCallsBeforeReturns(comp->trMemory()),61_classInfo(0),62_blocksToInline(blocksToInline),63_argPlaceholderSlot(argPlaceholderSlot),64_intrinsicErrorHandling(0),65_invokeSpecialInterface(NULL),66_invokeSpecialInterfaceCalls(NULL),67_invokeSpecialSeen(false),68_couldOSRAtNextBC(false),69_processedOSRNodes(NULL),70_invokeHandleCalls(NULL),71_invokeHandleGenericCalls(NULL),72_invokeDynamicCalls(NULL),73_ilGenMacroInvokeExactCalls(NULL),74_methodHandleInvokeCalls(NULL)75{76static const char *noLookahead = feGetEnv("TR_noLookahead");77_noLookahead = (noLookahead || comp->getOption(TR_DisableLookahead)) ? true : false;78_thisChanged = false;79if (80(forceClassLookahead ||81(comp->getNeedsClassLookahead() && !_noLookahead &&82((comp->getMethodHotness() >= scorching) ||83(comp->couldBeRecompiled() && (comp->getMethodHotness() >= hot ))))))84{85bool allowForAOT = comp->getOption(TR_UseSymbolValidationManager);86_classInfo = comp->getPersistentInfo()->getPersistentCHTable()->findClassInfoAfterLocking(method()->containingClass(), comp, allowForAOT);87}88else89{90if (!comp->getOption(TR_PerformLookaheadAtWarmCold))91_noLookahead = true;92}9394if (argPlaceholderSlot == -1)95{96_argPlaceholderSignatureOffset = 0xdead1127;97}98else99{100// Compute _argPlaceholderSignatureOffset101//102char *signatureChars = _methodSymbol->getResolvedMethod()->signatureChars();103TR_ASSERT(*signatureChars = '(', "assertion failure");104char *curArg = signatureChars+1;105int32_t argSlotsSkipped = methodSymbol->isStatic()? 0 : 1; // receiver doesn't appear in the signature106while (argSlotsSkipped < argPlaceholderSlot)107{108switch (*curArg)109{110case 'D':111case 'J':112argSlotsSkipped += 2;113break;114default:115argSlotsSkipped += 1;116break;117}118curArg = nextSignatureArgument(curArg);119}120_argPlaceholderSignatureOffset = curArg - signatureChars;121}122for( int i=0 ; i < _numDecFormatRenames ; i++ )123{124_decFormatRenamesDstSymRef[i] = NULL;125}126if (comp->getOption(TR_EnableOSR)127&& !comp->isPeekingMethod()128&& comp->isOSRTransitionTarget(TR::postExecutionOSR)129&& !_cannotAttemptOSR)130_processedOSRNodes = new (trStackMemory()) TR::NodeChecklist(comp);131}132133bool134TR_J9ByteCodeIlGenerator::genIL()135{136if (comp()->isOutermostMethod())137comp()->reportILGeneratorPhase();138139TR::StackMemoryRegion stackMemoryRegion(*trMemory());140141comp()->setCurrentIlGenerator(this);142143bool success = internalGenIL();144145if (success && !comp()->isPeekingMethod())146{147TR_SharedCache *sc = fej9()->sharedCache();148if (sc)149{150/*151* if DelayRelocationForAOT don't persist iprofiler info now.152* instead, persist iprofiler info when loading the aot compilation153*/154if (comp()->getOption(TR_DisableDelayRelocationForAOTCompilations) || !fej9()->shouldDelayAotLoad())155{156sc->persistIprofileInfo(_methodSymbol->getResolvedMethodSymbol(), comp());157}158}159}160161/*162* If we're generating IL for DecimalformatHelper.formatAsDouble(Float), replace163* the necessary fields, statics, and methods appropriately. This is part of164* the optimization that replaces df.format(bd.doubleValue()) and165* df.format(bd.floatValue()) with, respectively,166* DecimalFormatHelper.formatAsDouble(df, bd) and167* DecimalFormatHelper.formatAsFloat(df, bd) in which bd is a BigDecimal object168* and df is DecimalFormat object. The latter pair of calls are much faster than169* the former ones because it avoids many of the conversions that the former170* performs.171*/172if (success)173{174const char* methodName = _methodSymbol->signature(comp()->trMemory());175if (!strcmp(methodName, "com/ibm/jit/DecimalFormatHelper.formatAsDouble(Ljava/text/DecimalFormat;Ljava/math/BigDecimal;)Ljava/lang/String;") ||176!strcmp(methodName, "com/ibm/jit/DecimalFormatHelper.formatAsFloat(Ljava/text/DecimalFormat;Ljava/math/BigDecimal;)Ljava/lang/String;"))177success = success && replaceMembersOfFormat();178}179180if (success && !comp()->isPeekingMethod())181{182_methodSymbol->clearProfilingOffsetInfo();183for (TR::Block *block = _methodSymbol->getFirstTreeTop()->getEnclosingBlock(); block; block = block->getNextBlock())184_methodSymbol->addProfilingOffsetInfo(block->getEntry()->getNode()->getByteCodeIndex(), block->getExit()->getNode()->getByteCodeIndex());185}186187comp()->setCurrentIlGenerator(0);188189return success;190}191192bool TR_J9ByteCodeIlGenerator::internalGenIL()193{194_stack = new (trStackMemory()) TR_Stack<TR::Node *>(trMemory(), 20, false, stackAlloc);195196bool success = false;197198if ((method()->isNewInstanceImplThunk() || debug("testGenNewInstanceImplThunk")))199{200success = genNewInstanceImplThunk();201if (!success) // must jit the body (throw instantiation exception)202success = genILFromByteCodes();203else if (comp()->getOption(TR_EnableOSR) && !comp()->isPeekingMethod() && !comp()->getOption(TR_FullSpeedDebug))204_methodSymbol->setCannotAttemptOSR(0);205206return success;207}208209TR::RecognizedMethod recognizedMethod = _methodSymbol->getRecognizedMethod();210if (recognizedMethod != TR::unknownMethod)211{212if (recognizedMethod == TR::com_ibm_jit_JITHelpers_supportsIntrinsicCaseConversion && !TR::Compiler->om.canGenerateArraylets())213{214if (performTransformation(comp(), "O^O IlGenerator: Generate com/ibm/jit/JITHelpers.supportsIntrinsicCaseConversion\n"))215{216genHWOptimizedStrProcessingAvailable();217return true;218}219}220221if (recognizedMethod == TR::com_ibm_dataaccess_DecimalData_JITIntrinsicsEnabled)222{223if (performTransformation(comp(), "O^O IlGenerator: Generate com/ibm/dataaccess/DecimalData.JITIntrinsicsEnabled\n"))224{225genJITIntrinsicsEnabled();226return true;227}228}229230if (recognizedMethod == TR::com_ibm_rmi_io_FastPathForCollocated_isVMDeepCopySupported)231{232if (performTransformation(comp(), "O^O IlGenerator: Generate com/ibm/rmi/io/FastPathForCollocated/isVMDeepCopySupported\n"))233{234genIsORBDeepCopyAvailable();235return true;236}237}238239if (!comp()->getOption(TR_DisableInliningOfNatives))240{241// If we're inlining then there are some stack walking routines that can be made faster242// by avoiding the stack walk.243//244TR_ResolvedMethod * caller1 = method()->owningMethod();245TR_ResolvedMethod * caller = caller1 ? caller1->owningMethod() : 0;246247if( caller && caller1)248{249TR_OpaqueClassBlock *callerClass = caller ? caller->classOfMethod() : 0;250TR_OpaqueClassBlock *callerClass1 = caller1 ? caller1->classOfMethod() : 0;251252bool doIt = !(fej9()->stackWalkerMaySkipFrames(caller->getPersistentIdentifier(),callerClass) ||253fej9()->stackWalkerMaySkipFrames(caller1->getPersistentIdentifier(),callerClass1));254255256if (doIt && !comp()->compileRelocatableCode())257{258if (recognizedMethod == TR::java_lang_ClassLoader_callerClassLoader)259{260createGeneratedFirstBlock();261// check for bootstrap classloader, if so262// return null (see semantics of ClassLoader.callerClassLoader())263//264if (fej9()->isClassLoadedBySystemClassLoader(caller->classOfMethod()))265{266loadConstant(TR::aconst, (void *)0);267}268else269{270loadSymbol(TR::aload, symRefTab()->findOrCreateClassLoaderSymbolRef(caller));271}272genTreeTop(TR::Node::create(method()->returnOpCode(), 1, pop()));273return true;274}275if (recognizedMethod == TR::com_ibm_oti_vm_VM_callerClass)276{277createGeneratedFirstBlock();278loadConstant(TR::aconst, caller->classOfMethod());279genTreeTop(TR::Node::create(method()->returnOpCode(), 1, pop()));280return true;281}282}283}284}285}286if (method()->isJNINative())287return genJNIIL();288289return genILFromByteCodes();290}291292bool293TR_J9ByteCodeIlGenerator::genILFromByteCodes()294{295// first passthrough of the byte code to see if this pointer has been changed296if (isThisChanged())297_thisChanged = true;298299initialize();300301// don't go peeking into massive methods302if (comp()->isPeekingMethod() && _maxByteCodeIndex >= USHRT_MAX/8)303return false;304305// FSD sync object support306//307// Ideally, I'd like the sync object in FSD to work exactly as it does in the interpreter.308// This means that the sync object (receiver for instance methods, declaring class for309// static methods) is always stored in synthetic local N+1 after the stack frame is built,310// and is re-read from memory before use in the method monitor exit. If it's a lot of trouble311// to place it at N+1, the decompiler can read it from somewhere else as long as you can point me there312// via the metadata. Whatever slot is used, it must be marked as a GC reference even when it is a class.313// If we eventually support hot code replace which does not flush the JIT code caches, we'll314// need to do some more work for static methods, since the class sync object in static sync frames must always be the "current" class.315//316if (_methodSymbol->isSynchronised())317{318if (comp()->getOption(TR_FullSpeedDebug) || !comp()->getOption(TR_DisableLiveMonitorMetadata))319{320TR::SymbolReference * symRef;321if (comp()->getOption(TR_FullSpeedDebug))322symRef = symRefTab()->findOrCreateAutoSymbol(_methodSymbol, _methodSymbol->getSyncObjectTempIndex(), TR::Address);323else324symRef = symRefTab()->createTemporary(_methodSymbol, TR::Address);325326_methodSymbol->setSyncObjectTemp(symRef);327328if (!comp()->getOption(TR_DisableLiveMonitorMetadata))329{330symRef->setHoldsMonitoredObjectForSyncMethod();331comp()->addAsMonitorAuto(symRef, true);332}333}334}335336if (_methodSymbol->getResolvedMethod()->isNonEmptyObjectConstructor())337{338if (comp()->getOption(TR_FullSpeedDebug))339{340TR::SymbolReference *symRef = symRefTab()->findOrCreateAutoSymbol(_methodSymbol, _methodSymbol->getThisTempForObjectCtorIndex(), TR::Address);341_methodSymbol->setThisTempForObjectCtor(symRef);342symRef->getSymbol()->setThisTempForObjectCtor();343}344}345346_staticFieldReferenceEncountered = false;347_staticMethodInvokeEncountered = false;348349// Allocate zero-length bit vectors before walker so that the bit vectors can grow on the right350// stack memory region351//352_methodHandleInvokeCalls = new (trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc, growable);353_invokeHandleCalls = new (trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc, growable);354_invokeHandleGenericCalls = new (trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc, growable);355_invokeDynamicCalls = new (trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc, growable);356_ilGenMacroInvokeExactCalls = new (trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc, growable);357358TR::Block * lastBlock = walker(0);359360if (hasExceptionHandlers())361lastBlock = genExceptionHandlers(lastBlock);362363_bcIndex = 0;364365_methodSymbol->setFirstTreeTop(blocks(0)->getEntry());366367if (inliningCheckIfFinalizeObjectIsBeneficial())368{369inlineJitCheckIfFinalizeObject(blocks(0));370}371372prependEntryCode(blocks(0));373374if (!comp()->getOption(TR_DisableGuardedCountingRecompilations) &&375comp()->getRecompilationInfo() && comp()->getRecompilationInfo()->shouldBeCompiledAgain() &&376!comp()->getRecompilationInfo()->isRecompilation() && // only do it for first time compilations377(!comp()->getPersistentInfo()->_countForRecompile || comp()->getOption(TR_EnableMultipleGCRPeriods)) &&378comp()->isOutermostMethod() &&379comp()->getOptions()->getInsertGCRTrees() &&380!comp()->isDLT() && !method()->isJNINative())381{382// GCR filtering: Do not insert GCR trees for methods that are small and have no calls383// This code is better suited for CompilationThread.cpp384// but we need support from VM to tell us that a method has calls385if (_methodSymbol->mayHaveInlineableCall() ||386// Possible tweak: increase the threshold for methods that do not have loops387_maxByteCodeIndex > TR::Options::_smallMethodBytecodeSizeThresholdForCold ||388_methodSymbol->mayHaveLoops())389{390prependGuardedCountForRecompilation(comp()->getStartTree()->getNode()->getBlock());391comp()->getOptimizationPlan()->resetAddToUpgradeQueue(); // do not add to upgrade queue methods for which we used GCR392// stats393comp()->getPersistentInfo()->incNumGCRBodies();394}395else396{397//TR_VerboseLog::writeLineLocked(TR_Vlog_PERF,"Saved a GCR gen body nmayHaveInlineableCall=%d mayHaveLoops=%d _maxByteCodeIndex=%d\n", _methodSymbol->mayHaveInlineableCall(), _methodSymbol->mayHaveLoops(), _maxByteCodeIndex);398// stats399comp()->getPersistentInfo()->incNumGCRSaves();400}401}402403// Logic related to SamplingJProfiling404//405if (comp()->isOutermostMethod() && // Only do it once for the method to be compiled406!comp()->getOptions()->isDisabled(OMR::samplingJProfiling)) // If heuristic enabled samplingJProfiling for this body407{408// Verify that the GCR logic above actually inserted GCR trees409// or that this is a DLT body410// Also verify that method has bytecodes we want to profile (invokes/checkcasts/branches)411//412if ((comp()->isDLT() || (comp()->getRecompilationInfo() &&413comp()->getRecompilationInfo()->getJittedBodyInfo()->getUsesGCR()))414&& (_methodSymbol->mayHaveInlineableCall()415|| _methodSymbol->hasCheckcastsOrInstanceOfs()416|| _methodSymbol->hasBranches())417)418{419// Disable inlining to compile fast and avoid the bug with not profiling on the fast path420comp()->getOptions()->setDisabled(OMR::inlining, true);421}422else // Canot profile or there is nothing to profile; take corrective actions423{424// Disable the samplingJProfiling opt425comp()->getOptions()->setDisabled(OMR::samplingJProfiling, true);426427// If the opt level was reduced to cold solely because we wanted428// to do samplingJProfiling then we must move the opt level back to warm429if (comp()->getOptimizationPlan()->isDowngradedDueToSamplingJProfiling())430{431comp()->changeOptLevel(warm);432comp()->getOptimizationPlan()->setDowngradedDueToSamplingJProfiling(false);433comp()->getOptimizationPlan()->setOptLevelDowngraded(false);434}435}436}437438439// Code pertaining to the secondary/upgrade compilation queue440// If the method is small, doesn't have loops or calls, then do not try to upgrade it441if (comp()->isOutermostMethod() && comp()->getOptimizationPlan()->shouldAddToUpgradeQueue())442{443if (!_methodSymbol->mayHaveInlineableCall() && !_methodSymbol->mayHaveLoops() &&444_maxByteCodeIndex <= TR::Options::_smallMethodBytecodeSizeThresholdForCold)445comp()->getOptimizationPlan()->resetAddToUpgradeQueue();446}447448// the optimizer assumes that the ilGenerator doesn't gen code for449// unreachable blocks. An exception handler may be unreachable.450//451if (hasExceptionHandlers())452cfg()->removeUnreachableBlocks();453454int32_t fpIndex = hasFPU() ? -1 : findFloatingPointInstruction();455if (fpIndex != -1) _unimplementedOpcode = _code[fpIndex];456457if (_unimplementedOpcode)458{459_methodSymbol->setUnimplementedOpcode(_unimplementedOpcode);460461if (debug("traceInfo"))462{463if (_unimplementedOpcode == 255)464diagnostic("\nUnimplemented opcodes found\n");465else466diagnostic("\nUnimplemented opcode found: %s(%d)\n",467((TR_J9VM *)fej9())->getByteCodeName(_unimplementedOpcode), _unimplementedOpcode);468}469470if (!debug("continueWithUnimplementedOpCode"))471return false;472}473474//if (!_thisChanged)475//setThisNonNullProperty(_methodSymbol->getFirstTreeTop(), comp());476477bool needMonitor = _methodSymbol->isSynchronised() && !comp()->getOption(TR_DisableLiveMonitorMetadata);478int32_t numMonents = 0;479int32_t numMonexits = 0;480bool primitive = true;481TR::TreeTop *monentStore = NULL;482TR::TreeTop *monexitStore = NULL;483TR::Node *monentTree = NULL;484TR::Node *monexitTree = NULL;485TR::TreeTop *currTree = _methodSymbol->getFirstTreeTop()->getNextTreeTop();486487List<TR::SymbolReference> autoOrParmSymRefList(comp()->trMemory());488TR_ScratchList<TR::TreeTop> unresolvedCheckcastTopsNeedingNullGuard(comp()->trMemory());489TR_ScratchList<TR::TreeTop> unresolvedInstanceofTops(comp()->trMemory());490TR_ScratchList<TR::TreeTop> invokeSpecialInterfaceTops(comp()->trMemory());491TR::NodeChecklist evaluatedInvokeSpecialCalls(comp());492TR::NodeChecklist evaluatedMethodHandleInvokeCalls(comp());493TR_BoolArrayStoreTransformer::NodeSet bstoreiUnknownArrayTypeNodes(std::less<TR::Node *>(), comp()->trMemory()->currentStackRegion());494TR_BoolArrayStoreTransformer::NodeSet bstoreiBoolArrayTypeNodes(std::less<TR::Node *>(), comp()->trMemory()->currentStackRegion());495TR_BoolArrayStoreTransformer boolArrayStoreTransformer(&bstoreiUnknownArrayTypeNodes, &bstoreiBoolArrayTypeNodes);496497for (; currTree != NULL; currTree = currTree->getNextTreeTop())498{499TR::Node *currNode = currTree->getNode();500TR::ILOpCode opcode = currNode->getOpCode();501502if (currNode->getNumChildren() >= 1503&& currNode->getFirstChild()->getOpCode().isCall()504&& !currNode->getFirstChild()->getSymbol()->castToMethodSymbol()->isHelper()505&& _methodHandleInvokeCalls->isSet(currNode->getFirstChild()->getByteCodeIndex())506&& !evaluatedMethodHandleInvokeCalls.contains(currNode->getFirstChild()))507{508expandMethodHandleInvokeCall(currTree);509evaluatedMethodHandleInvokeCalls.add(currNode->getFirstChild());510continue;511}512513if ((opcode.isStoreDirect() && opcode.hasSymbolReference() && currNode->getSymbolReference()->getSymbol()->isAutoOrParm()) ||514opcode.isCheckCast())515{516TR::SymbolReference *symRef = currNode->getSymbolReference();517TR::Node *typeNode = NULL;518if (opcode.isStoreDirect())519typeNode = currNode->getFirstChild(); // store auto520else typeNode = currNode->getSecondChild(); // checkcast521if (boolArrayStoreTransformer.isAnyDimensionBoolArrayNode(typeNode))522boolArrayStoreTransformer.setHasBoolArrayAutoOrCheckCast();523else if (boolArrayStoreTransformer.isAnyDimensionByteArrayNode(typeNode))524boolArrayStoreTransformer.setHasByteArrayAutoOrCheckCast();525526if (opcode.isStoreDirect() && symRef->getSymbol()->isParm() && currNode->getDataType() == TR::Address)527{528int lhsLength;529int rhsLength;530const char *lhsSig = currNode->getTypeSignature(lhsLength, stackAlloc, false /* parmAsAuto */);531const char *rhsSig = typeNode->getTypeSignature(rhsLength, stackAlloc, true /* parmAsAuto */);532if (!lhsSig || !rhsSig || lhsLength != rhsLength || strncmp(lhsSig, rhsSig, lhsLength))533boolArrayStoreTransformer.setHasVariantArgs();534}535}536else if (opcode.getOpCodeValue() == TR::bstorei && currNode->getSymbolReference()->getCPIndex() == -1537&& currNode->getFirstChild()->isInternalPointer())538{539TR::Node *arrayBase = currNode->getFirstChild()->getFirstChild();540if (arrayBase->getOpCode().hasSymbolReference())541{542if (boolArrayStoreTransformer.isBoolArrayNode(arrayBase))543{544if (comp()->getOption(TR_TraceILGen))545traceMsg(comp(), "bstorei node n%dn is bool array store\n", currNode->getGlobalIndex());546bstoreiBoolArrayTypeNodes.insert(currNode);547}548else if (!boolArrayStoreTransformer.isByteArrayNode(arrayBase))549bstoreiUnknownArrayTypeNodes.insert(currNode);550}551else552bstoreiUnknownArrayTypeNodes.insert(currNode);553}554555if (currNode->getOpCodeValue() == TR::checkcast556&& currNode->getSecondChild()->getOpCodeValue() == TR::loadaddr557&& currNode->getSecondChild()->getSymbolReference()->isUnresolved()558&& // check whether the checkcast class is valuetype. Expansion is only needed for checkcast to reference type.559(!TR::Compiler->om.areValueTypesEnabled()560|| !TR::Compiler->cls.isClassRefValueType(comp(), method()->classOfMethod(), currNode->getSecondChild()->getSymbolReference()->getCPIndex())))561{562unresolvedCheckcastTopsNeedingNullGuard.add(currTree);563}564else if (currNode->getOpCodeValue() == TR::treetop565&& currNode->getFirstChild()->getOpCodeValue() == TR::instanceof566&& currNode->getFirstChild()->getSecondChild()->getOpCodeValue() == TR::loadaddr567&& currNode->getFirstChild()->getSecondChild()->getSymbolReference()->isUnresolved())568{569unresolvedInstanceofTops.add(currTree);570}571else if (_invokeSpecialInterfaceCalls != NULL572&& currNode->getNumChildren() >= 1573&& currNode->getFirstChild()->getOpCode().isCallDirect()574&& !currNode->getFirstChild()->isPotentialOSRPointHelperCall()575&& _invokeSpecialInterfaceCalls->isSet(576currNode->getFirstChild()->getByteCodeIndex())577&& !evaluatedInvokeSpecialCalls.contains(currNode->getFirstChild()))578{579evaluatedInvokeSpecialCalls.add(currNode->getFirstChild());580invokeSpecialInterfaceTops.add(currTree);581}582583// modify the vftChild584// If the receiver pointer is a simple load of an auto or parm, then clone585// it rather than incrementing its reference count. This can prevent the586// inliner from creating unnecessary temporaries. The special case is when587// there is a store to the auto or parm between the load of receiver pointer588//and the virtual function call589590//keep track of the symbol references of auto or parm changed by stores591if(opcode.isStoreDirect() && opcode.hasSymbolReference())592{593TR::SymbolReference *symRef = currNode->getSymbolReference();594if (symRef && symRef->getSymbol()->isAutoOrParm())595autoOrParmSymRefList.add(symRef);596}597598if(opcode.isResolveOrNullCheck())599{600TR::Node *firstChild = currNode->getFirstChild();601opcode = firstChild->getOpCode(); // the first child is indirect call to method602if (opcode.isCallIndirect()603&& !firstChild->getSymbol()->castToMethodSymbol()->isComputed())604{605TR::Node *receiver;606TR::Node *firstGrandChild = firstChild->getFirstChild(); // firstGrandChild is the vft child607receiver = firstGrandChild->getFirstChild();608TR::ILOpCode receiverOpcode = receiver->getOpCode();609TR::SymbolReference *symRef = NULL;610if(receiverOpcode.hasSymbolReference() && receiverOpcode.isLoadVarDirect())611symRef = receiver->getSymbolReference();612bool canCopyReceiver =symRef && symRef->getSymbol()->isAutoOrParm() && !autoOrParmSymRefList.find(symRef);613if (canCopyReceiver)614{615TR::Node *newReceiver = TR::Node::copy(receiver);616newReceiver->setReferenceCount(1);617firstGrandChild->setChild(0, newReceiver);618receiver->decReferenceCount();619}620}621}622623if (needMonitor && primitive)624{625if ((currNode->getOpCode().isStore() &&626currNode->getSymbol()->holdsMonitoredObject() &&627!currNode->isLiveMonitorInitStore()) || currNode->getOpCode().getOpCodeValue() == TR::monexitfence)628{629bool isMonent = currNode->getOpCode().getOpCodeValue() != TR::monexitfence;630if (isMonent)631monentStore = currTree;632else633monexitStore = currTree;634}635636if ((currNode->getOpCodeValue() == TR::monexit) || (currNode->getOpCodeValue() == TR::monent))637{638if (currNode->getOpCodeValue() == TR::monexit)639{640if (numMonexits > 0)641{642primitive = false;643continue;644}645646monexitTree = currNode;647numMonexits++;648}649else if (currNode->getOpCodeValue() == TR::monent)650{651if (numMonents > 0)652{653primitive = false;654continue;655}656657monentTree = currNode;658numMonents++;659}660}661else if (currNode->getNumChildren() > 0 &&662currNode->getFirstChild()->getNumChildren() > 0 &&663((currNode->getFirstChild()->getOpCodeValue() == TR::monexit) || (currNode->getFirstChild()->getOpCodeValue() == TR::monent)))664{665if (currNode->getFirstChild()->getOpCodeValue() == TR::monexit)666{667if (numMonexits > 0)668{669primitive = false;670continue;671}672monexitTree = currNode->getFirstChild();673numMonexits++;674}675else if (currNode->getFirstChild()->getOpCodeValue() == TR::monent)676{677if (numMonents > 0)678{679primitive = false;680continue;681}682monentTree = currNode->getFirstChild();683numMonents++;684}685}686else if (currNode->exceptionsRaised() != 0 ||687currNode->canCauseGC())688{689primitive = false;690continue;691}692}693}694695if( needMonitor)696{697if (primitive &&698monentTree &&699monexitTree &&700monentStore &&701monexitStore)702{703TR::SymbolReference *replaceSymRef = NULL;704if (monentStore->getNode()->getFirstChild()->getSymbolReference()->getSymbol()->isAutoOrParm())705replaceSymRef = monentStore->getNode()->getFirstChild()->getSymbolReference();706707if (replaceSymRef)708{709if (monentTree->getFirstChild()->getSymbolReference()->getSymbol()->isAutoOrParm())710{711monentTree->getFirstChild()->setSymbolReference(replaceSymRef);712}713714if (monexitTree->getFirstChild()->getSymbolReference()->getSymbol()->isAutoOrParm())715{716monexitTree->getFirstChild()->setSymbolReference(replaceSymRef);717}718719TR::TreeTop *prev = monentStore->getPrevTreeTop();720TR::TreeTop *next = monentStore->getNextTreeTop();721monentStore->getNode()->recursivelyDecReferenceCount();722prev->join(next);723724prev = monexitStore->getPrevTreeTop();725next = monexitStore->getNextTreeTop();726monexitStore->getNode()->recursivelyDecReferenceCount();727prev->join(next);728_methodSymbol->setSyncObjectTemp(NULL);729}730}731}732733{734ListIterator<TR::TreeTop> it(&unresolvedCheckcastTopsNeedingNullGuard);735for (TR::TreeTop *tree = it.getCurrent(); tree != NULL; tree = it.getNext())736expandUnresolvedClassCheckcast(tree);737}738{739ListIterator<TR::TreeTop> it(&unresolvedInstanceofTops);740for (TR::TreeTop *tree = it.getCurrent(); tree != NULL; tree = it.getNext())741expandUnresolvedClassInstanceof(tree);742}743{744ListIterator<TR::TreeTop> it(&invokeSpecialInterfaceTops);745for (TR::TreeTop *tree = it.getCurrent(); tree != NULL; tree = it.getNext())746expandInvokeSpecialInterface(tree);747}748749if (!bstoreiUnknownArrayTypeNodes.empty() || !bstoreiBoolArrayTypeNodes.empty())750boolArrayStoreTransformer.perform();751752return true;753}754755756TR::Block *757TR_J9ByteCodeIlGenerator::cloneHandler(TryCatchInfo * handlerInfo, TR::Block * firstBlock, TR::Block *lastBlock, TR::Block *lastBlockInMethod, List<TR::Block> *clonedCatchBlocks)758{759TR_BlockCloner cloner(cfg());760handlerInfo->_firstBlock = cloner.cloneBlocks(firstBlock, lastBlock);761lastBlockInMethod->getExit()->join(handlerInfo->_firstBlock->getEntry());762handlerInfo->_lastBlock = lastBlockInMethod = cloner.getLastClonedBlock();763handlerInfo->_catchBlock = cloner.getToBlock(firstBlock);764765TR::Block *cursorBlock = firstBlock;766while (cursorBlock != lastBlockInMethod)767{768clonedCatchBlocks->add(cursorBlock);769cursorBlock = cursorBlock->getNextBlock();770}771clonedCatchBlocks->add(cursorBlock);772773cfg()->addSuccessorEdges(lastBlockInMethod);774return lastBlockInMethod;775}776777778779TR::Block *780TR_J9ByteCodeIlGenerator::genExceptionHandlers(TR::Block * lastBlock)781{782bool trace = comp()->getOption(TR_TraceILGen);783_inExceptionHandler = true;784TR::SymbolReference * catchObjectSymRef = symRefTab()->findOrCreateExcpSymbolRef();785uint16_t i;786List<TR::Block> clonedCatchBlocks(comp()->trMemory());787788for (auto handlerInfoIter = _tryCatchInfo.begin(); handlerInfoIter != _tryCatchInfo.end(); ++handlerInfoIter)789{790TryCatchInfo & handlerInfo = *handlerInfoIter;791uint16_t firstIndex = handlerInfo._handlerIndex;792793// Two exception data entries can have ranges pointing at the same handler.794// If the types are different then we have to clone the handler.795796//797//Partial Inlining - Deal with exception Handlers798//799if(_blocksToInline && !_blocksToInline->isInExceptionList(firstIndex)) //Case 1: item is not in exception list, therefore no ilgen to be done on it800{801continue; // nothing to be done for this handler!802}803else if (804_blocksToInline805&& _blocksToInline->isInExceptionList(firstIndex)806&& !_blocksToInline->isInList(firstIndex)807&& !isGenerated(firstIndex)) //Case 2: item is in exception list, but not in list of blocks to be ilgen'd808{809_blocksToInline->hasGeneratedRestartTree() ? genGotoPartialInliningCallBack(firstIndex,_blocksToInline->getGeneratedRestartTree()) :810_blocksToInline->setGeneratedRestartTree(genPartialInliningCallBack(firstIndex,_blocksToInline->getCallNodeTreeTop()));811handlerInfo._lastBlock = blocks(firstIndex);812handlerInfo._firstBlock = blocks(firstIndex);813handlerInfo._catchBlock = blocks(firstIndex);814815blocks(firstIndex)->setIsAdded();816if(blocks(firstIndex) != _blocksToInline->getGeneratedRestartTree()->getEnclosingBlock())817{818lastBlock->getExit()->join(blocks(firstIndex)->getEntry());819cfg()->addNode(blocks(firstIndex));820cfg()->addEdge(blocks(firstIndex),_blocksToInline->getGeneratedRestartTree()->getEnclosingBlock());821}822else823{824lastBlock->getExit()->join(blocks(firstIndex)->getEntry());825cfg()->insertBefore(blocks(firstIndex),cfg()->getEnd()->asBlock());826}827lastBlock=handlerInfo._lastBlock;828//ok what I'm trying here is saying that my first block, last block and catchblock in my catcher are all the same (the one block)829830handlerInfo._catchBlock->setHandlerInfo(handlerInfo._catchType, (uint8_t)comp()->getInlineDepth(), handlerInfoIter - _tryCatchInfo.begin(), method(), comp());831continue;832}833834835bool generateNewBlock = true;836TR::Block * handlerBlockFromNonExceptionControlFlow = 0;837if (isGenerated(firstIndex))838{839generateNewBlock = false;840TryCatchInfo * dupHandler = 0;841for (int32_t j = 0; j < (handlerInfoIter - _tryCatchInfo.begin()); ++j)842{843TryCatchInfo & h = _tryCatchInfo[j];844if (h._handlerIndex == firstIndex)845{846if (!dupHandler)847dupHandler = &h;848if (h._catchType == handlerInfo._catchType)849{850dupHandler = &h;851break;852}853}854}855856if (!dupHandler)857{858handlerBlockFromNonExceptionControlFlow = _blocks[firstIndex];859generateNewBlock = true;860861// this handler must also be reachable from the mainline code....we don't862// know how to handle this yet863// todo: figure out how to handle this.864//865// TR_ASSERT(dupHandler, "can't figure out why the handler is already generated");866// comp()->failCompilation<TR::CompilationException>("can't figure out why the handler is already generated");867}868869if (!generateNewBlock)870{871if (handlerInfo._catchType != dupHandler->_catchType)872{873lastBlock = cloneHandler(&handlerInfo, dupHandler->_firstBlock, dupHandler->_lastBlock, lastBlock, &clonedCatchBlocks);874/*875TR_BlockCloner cloner(cfg());876handlerInfo->_firstBlock = cloner.cloneBlocks(dupHandler->_firstBlock, dupHandler->_lastBlock);877lastBlock->getExit()->join(handlerInfo->_firstBlock->getEntry());878handlerInfo->_lastBlock = lastBlock = cloner.getLastClonedBlock();879handlerInfo->_catchBlock = cloner.getToBlock(blocks(firstIndex));880cfg()->addSuccessorEdges(lastBlock);881*/882}883else884handlerInfo._catchBlock = dupHandler->_catchBlock;885}886}887888if (generateNewBlock)889{890setupBBStartContext(firstIndex);891892TR::SymbolReference *exceptionLoadSymRef = NULL;893if (handlerBlockFromNonExceptionControlFlow &&894_stack->topIndex() == 0)895{896TR::Node *exceptionLoadOnStack = _stack->top();897if (exceptionLoadOnStack->getOpCode().isLoadVarDirect() &&898exceptionLoadOnStack->getOpCode().hasSymbolReference() &&899exceptionLoadOnStack->getSymbolReference()->getSymbol()->isAutoOrParm())900{901exceptionLoadSymRef = exceptionLoadOnStack->getSymbolReference();902//dumpOptDetails("exc load on stack = %p\n", exceptionLoadOnStack);903}904}905906_bcIndex = firstIndex;907908// The stack at the start of a catch block only contains the catch object909loadSymbol(TR::aload, catchObjectSymRef);910if (_compilation->getHCRMode() == TR::osr || _compilation->getOSRMode() == TR::involuntaryOSR)911{912genTreeTop(TR::Node::createWithSymRef(_block->getEntry()->getNode(), TR::asynccheck, 0,913symRefTab()->findOrCreateAsyncCheckSymbolRef(_methodSymbol)));914915// Under NextGenHCR, the commoned catch object will now be on the stack. This results916// in the addition of an unneeded temp if the block is split here. Short cut this by917// uncommoning them.918if (_compilation->getHCRMode() == TR::osr)919{920pop();921loadSymbol(TR::aload, catchObjectSymRef);922}923}924925/*926* Spill the exception object into a temporary if it isn't immediately done so927* in the catch block. This is necessary because the exception object will not928* be preserved across method calls (and for a handful of other reasons) and929* cannot be materialized from the metadata. A stack temp is necessary in this930* case.931*/932uint8_t firstOpCode = _code[_bcIndex];933int32_t bc = convertOpCodeToByteCodeEnum(firstOpCode);934935if (bc != J9BCastore)936{937TR::SymbolReference *exceptionObjectSymRef = symRefTab()->createTemporary(_methodSymbol, TR::Address);938TR::Node *exceptionNode = pop();939genTreeTop(TR::Node::createStore(exceptionObjectSymRef, exceptionNode));940loadConstant(TR::aconst, (void *)0);941genTreeTop(TR::Node::createStore(exceptionNode->getSymbolReference(), pop()));942loadSymbol(TR::aload, exceptionObjectSymRef);943if (trace)944traceMsg(comp(), "catch block first BC is not an astore, inserting explicit store of exception object\n");945}946947TR::Node *node = _stack->top();948node->setIsNonNull(true);949950TR::TreeTop *storeTree = NULL;951if (handlerBlockFromNonExceptionControlFlow)952{953if (!exceptionLoadSymRef)954{955comp()->failCompilation<TR::ILGenFailure>("Aborting at generate exception handlers");956}957else958{959TR::Node *storeNode = TR::Node::createStore(exceptionLoadSymRef, pop());960storeTree = TR::TreeTop::create(comp(), storeNode);961}962963TR::Node *lastNode = handlerBlockFromNonExceptionControlFlow->getLastRealTreeTop()->getNode();964if (lastNode->getOpCode().isResolveOrNullCheck() ||965(lastNode->getOpCodeValue() == TR::treetop))966lastNode = lastNode->getFirstChild();967968//traceMsg(comp(), "last node %p bc index %d and opcode %s\n", lastNode, lastNode->getByteCodeIndex(), lastNode->getOpCode().getName());969970TR::ILOpCode &lastOpCode = lastNode->getOpCode();971if (!lastOpCode.isGoto() &&972!lastOpCode.isReturn() &&973(lastOpCode.getOpCodeValue() != TR::athrow))974{975comp()->failCompilation<TR::ILGenFailure>("Aborting: not goto, not return and not a throw.");976}977}978979if (handlerBlockFromNonExceptionControlFlow)980{981lastBlock = cloneHandler(&handlerInfo, handlerBlockFromNonExceptionControlFlow, handlerBlockFromNonExceptionControlFlow, lastBlock, &clonedCatchBlocks);982lastBlock->prepend(storeTree);983}984else985{986handlerInfo._lastBlock = walker(lastBlock);987handlerInfo._firstBlock = lastBlock->getNextBlock();988handlerInfo._catchBlock = blocks(firstIndex);989lastBlock = handlerInfo._lastBlock;990}991}992993handlerInfo._catchBlock->setHandlerInfo(handlerInfo._catchType, (uint8_t)comp()->getInlineDepth(), handlerInfoIter - _tryCatchInfo.begin(), method(), comp());994}995996for (auto handlerInfoIter = _tryCatchInfo.begin(); handlerInfoIter != _tryCatchInfo.end(); ++handlerInfoIter)997{998TryCatchInfo & handlerInfo = *handlerInfoIter;999if(_blocksToInline && !_blocksToInline->isInExceptionList(handlerInfo._handlerIndex)) //Case 1: item is not in exception list, therefore no ilgen to be done on it1000{1001continue; // nothing to be done for this handler!1002}1003TR::Block *catchBlock = handlerInfo._catchBlock;1004TR::Block *restartBlock = _blocksToInline? _blocksToInline->getGeneratedRestartTree()->getEnclosingBlock() : NULL;1005uint8_t precedingOpcode = _code[handlerInfo._startIndex-1];1006TR_J9ByteCode precedingBytecode = convertOpCodeToByteCodeEnum(precedingOpcode);1007uint8_t lastOpcode = _code[handlerInfo._endIndex];1008TR_J9ByteCode lastBytecode = convertOpCodeToByteCodeEnum(lastOpcode);1009bool isSynchronizedRegion = (precedingBytecode == J9BCmonitorenter && lastBytecode == J9BCmonitorexit);1010if (isSynchronizedRegion) // monitorenter preceding try region that ends in monitorexit means synchronized1011catchBlock->setIsSynchronizedHandler();10121013for (uint16_t j = handlerInfo._startIndex; j <= handlerInfo._endIndex; ++j)1014if (blocks(j) && cfg()->getNodes().find(blocks(j)))1015{1016if (blocks(j) == catchBlock)1017{1018_methodSymbol->setMayHaveNestedLoops(true);1019}10201021if (blocks(j) != restartBlock)1022{1023cfg()->addExceptionEdge(blocks(j), catchBlock);1024ListIterator<TR::Block> clonedIt(&clonedCatchBlocks);1025for (TR::Block * cb = clonedIt.getFirst(); cb; cb = clonedIt.getNext())1026{1027if (cb->getEntry()->getNode()->getByteCodeIndex() == j)1028cfg()->addExceptionEdge(cb, catchBlock);1029}1030}1031}1032}10331034_inExceptionHandler = false;1035return lastBlock;1036}10371038TR::Node *1039TR_J9ByteCodeIlGenerator::genMethodEnterHook()1040{1041if (method()->isStatic())1042return TR::Node::createWithSymRef(TR::MethodEnterHook, 0, symRefTab()->findOrCreateReportStaticMethodEnterSymbolRef(_methodSymbol));10431044loadAuto(TR::Address, 0);1045return TR::Node::createWithSymRef(TR::MethodEnterHook, 1, 1, pop(), symRefTab()->findOrCreateReportMethodEnterSymbolRef(_methodSymbol));1046}10471048void1049TR_J9ByteCodeIlGenerator::prependEntryCode(TR::Block * firstBlock)1050{1051bool trace = comp()->getOption(TR_TraceILGen);1052TR::Node * monitorEnter = 0;1053TR::Node * syncObjectStore = 0;1054TR::Node * thisObjectStore = 0;1055TR::TreeTop * nhrttCheckTree1 = 0, * nhrttCheckTree2 = 0, * nhrttCheckTree3 = 0, * nhrttCheckTree4 = 0;1056TR::Node * lockObject = 0;1057if (_methodSymbol->isSynchronised())1058{1059loadMonitorArg();10601061TR::Node * firstChild = pop();1062TR::SymbolReference * monEnterSymRef = symRefTab()->findOrCreateMethodMonitorEntrySymbolRef(_methodSymbol);10631064if (firstChild->getOpCodeValue() == TR::loadaddr && firstChild->getSymbol()->isClassObject())1065{1066monitorEnter = TR::Node::createWithSymRef(TR::aloadi, 1, 1, firstChild, symRefTab()->findOrCreateJavaLangClassFromClassSymbolRef());1067monitorEnter = TR::Node::createWithSymRef(TR::monent, 1, 1, monitorEnter, monEnterSymRef);1068}1069else1070{1071monitorEnter = TR::Node::createWithSymRef(TR::monent, 1, 1, firstChild, monEnterSymRef);1072}10731074monitorEnter->setSyncMethodMonitor(true);1075TR_OpaqueClassBlock * owningClass = _methodSymbol->getResolvedMethod()->containingClass();1076if (owningClass != comp()->getObjectClassPointer())1077{1078monitorEnter->setSecond((TR::Node*)owningClass);1079if (trace)1080traceMsg(comp(), "setting class for %p to be %p\n", monitorEnter, owningClass);1081}10821083_methodSymbol->setMayContainMonitors(true);10841085if (_methodSymbol->isStatic())1086monitorEnter->setStaticMonitor(true);10871088// Store the receiver object to a temporary to deal with the case where the bytecode has been hacked1089// to write to the receiver. The temporary will be used on the monitor exit1090//1091if (_methodSymbol->getSyncObjectTemp())1092{1093if (_methodSymbol->isStatic())1094loadSymbol(TR::loadaddr, symRefTab()->findOrCreateClassSymbol(_methodSymbol, 0, method()->containingClass()));1095else1096loadAuto(TR::Address, 0);10971098lockObject = pop();1099if (monitorEnter->getFirstChild()->getOpCodeValue() == TR::aloadi &&1100monitorEnter->getFirstChild()->getSymbolReference() == symRefTab()->findJavaLangClassFromClassSymbolRef())1101lockObject = monitorEnter->getFirstChild();1102syncObjectStore = TR::Node::createStore(_methodSymbol->getSyncObjectTemp(), lockObject);1103}1104}11051106// if the receiver of Object.<init> has been written into, then we need to save a copy of the receiver into1107// a temporary and use that in the call to the finalizer1108//1109if (_methodSymbol->getThisTempForObjectCtor())1110{1111loadAuto(TR::Address, 0);1112thisObjectStore = TR::Node::createStore(_methodSymbol->getThisTempForObjectCtor(), pop());1113}11141115TR::Node * methodEnterHook = 0;11161117static const char* disableMethodHookForCallees = feGetEnv("TR_DisableMethodHookForCallees");1118if ((fej9()->isMethodTracingEnabled(_methodSymbol->getResolvedMethod()->getPersistentIdentifier())1119|| (!comp()->getOption(TR_FullSpeedDebug)1120&& TR::Compiler->vm.canMethodEnterEventBeHooked(comp())))1121&& (isOutermostMethod() || !disableMethodHookForCallees))1122{1123methodEnterHook = genMethodEnterHook();1124}11251126if (methodEnterHook || monitorEnter)1127{1128// If there's a branch to the first byte code then we have to prepend1129// the monitor enter and/or entry hook into its own block1130//1131if ((firstBlock->getPredecessors().size() > 1) || !isOutermostMethod())1132firstBlock = _methodSymbol->prependEmptyFirstBlock();11331134if (methodEnterHook)1135firstBlock->prepend(TR::TreeTop::create(comp(), methodEnterHook));11361137TR::TreeTop *syncObjectTT = NULL;1138if (syncObjectStore)1139syncObjectTT = TR::TreeTop::create(comp(), syncObjectStore);11401141if (monitorEnter)1142firstBlock->prepend(TR::TreeTop::create(comp(), monitorEnter));11431144if (nhrttCheckTree3)1145firstBlock->prepend(nhrttCheckTree3);11461147if (nhrttCheckTree2)1148firstBlock->prepend(nhrttCheckTree2);11491150if (nhrttCheckTree1)1151firstBlock->prepend(nhrttCheckTree1);11521153// the sync object store must be the first thing here, or everything above it will load a bad object reference1154if (syncObjectTT)1155firstBlock->prepend(syncObjectTT);1156}11571158if (thisObjectStore)1159{1160if (nhrttCheckTree4)1161firstBlock->prepend(nhrttCheckTree4);1162firstBlock->prepend(TR::TreeTop::create(comp(), thisObjectStore));1163}11641165if (comp()->isDLT() && isOutermostMethod())1166{1167genDLTransfer(firstBlock);1168}1169}11701171void1172TR_J9ByteCodeIlGenerator::prependGuardedCountForRecompilation(TR::Block * originalFirstBlock)1173{1174//1175// guardBlock: if (!countForRecompile) goto originalFirstBlock;1176// bumpCounterBlock: bodyInfo->count--;1177// if (bodyInfo->count > 0) goto originalFirstBlock;1178// callRecompileBlock: call jitRetranslateCallerWithPreparation(j9method, startPC);1179// bodyInfo->count=100001180// originalFirstBlock: ...1181//11821183bool trace = comp()->getOption(TR_TraceILGen);1184TR::TreeTop *originalFirstTree = _methodSymbol->getFirstTreeTop();1185TR::Node *node=originalFirstTree->getNode();11861187// construct guard1188TR::Block *guardBlock = TR::Block::createEmptyBlock(comp());1189TR::Node *cmpFlagNode;1190if (comp()->getOption(TR_ImmediateCountingRecompilation))1191{1192cmpFlagNode = TR::Node::createif(TR::ificmpeq, TR::Node::iconst(1234), TR::Node::iconst(5678), originalFirstBlock->getEntry());1193}1194else1195{1196TR::Node *loadFlagNode = TR::Node::createWithSymRef(node, TR::iload, 0, comp()->getSymRefTab()->findOrCreateCountForRecompileSymbolRef());11971198if (comp()->getOption(TR_EnableGCRPatching))1199cmpFlagNode = TR::Node::createif(TR::ificmpne, loadFlagNode, TR::Node::create(node, TR::iconst, 0, 1), originalFirstBlock->getEntry());1200else1201cmpFlagNode = TR::Node::createif(TR::ificmpeq, loadFlagNode, TR::Node::create(node, TR::iconst, 0, 0), originalFirstBlock->getEntry());1202}1203TR::TreeTop *cmpFlag = TR::TreeTop::create(comp(), cmpFlagNode);1204guardBlock->append(cmpFlag);1205TR::DebugCounter::prependDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "gcrMethods/byJittedBody/(%s)", comp()->signature()), cmpFlag, 1, TR::DebugCounter::Moderate);120612071208// construct counter bump1209TR::Block *bumpCounterBlock = TR::Block::createEmptyBlock(comp());1210TR::TreeTop * treeTop = TR::TreeTop::createIncTree(comp(), node, comp()->getRecompilationInfo()->getCounterSymRef(),1211-comp()->getOptions()->getGCRDecCount(), NULL, true);1212bumpCounterBlock->append(treeTop);1213TR::DebugCounter::prependDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "gcrCounterBumps/byJittedBody/(%s)", comp()->signature()), treeTop, 1, TR::DebugCounter::Free);1214TR::Node *bumpNode = treeTop->getNode()->getNumChildren() > 1 ? treeTop->getNode()->getSecondChild() : treeTop->getNode()->getFirstChild();12151216TR::Node *cmpCountNode = TR::Node::createif(TR::ificmpgt, bumpNode, TR::Node::create(TR::iconst, 0, 0), originalFirstBlock->getEntry());1217bumpCounterBlock->append(TR::TreeTop::create(comp(), cmpCountNode));1218bumpCounterBlock->setIsCold(true);1219bumpCounterBlock->setFrequency(UNKNOWN_COLD_BLOCK_COUNT);122012211222// construct call block1223TR::Block *callRecompileBlock = TR::Block::createEmptyBlock(comp());1224callRecompileBlock->append(TR::TreeTop::createResetTree(comp(), node, comp()->getRecompilationInfo()->getCounterSymRef(),1225comp()->getOptions()->getGCRResetCount(), NULL, true));12261227// Create the instruction that will patch my cmp1228if (comp()->getOption(TR_EnableGCRPatching))1229{1230TR::Node *constNode = TR::Node::create(node, TR::bconst, 0);1231constNode->setByte(2);1232callRecompileBlock->append(TR::TreeTop::create(comp(), TR::Node::createWithSymRef(TR::bstore, 1, 1, constNode,1233comp()->getSymRefTab()->findOrCreateGCRPatchPointSymbolRef())));1234}12351236TR::TreeTop *callTree = TR::TransformUtil::generateRetranslateCallerWithPrepTrees(node, TR_PersistentMethodInfo::RecompDueToGCR, comp());1237callRecompileBlock->append(callTree);1238callRecompileBlock->setIsCold(true);1239callRecompileBlock->setFrequency(UNKNOWN_COLD_BLOCK_COUNT);12401241// get all the blocks into the CFG1242if (trace) traceMsg(comp(), "adding edge start to guard\n");1243cfg()->addEdge(cfg()->getStart(), guardBlock);12441245if (trace) traceMsg(comp(), "insert before guard to bump\n");1246cfg()->insertBefore(guardBlock, bumpCounterBlock);1247if (trace) traceMsg(comp(), "insert before bump to call\n");1248cfg()->insertBefore(bumpCounterBlock, callRecompileBlock);1249if (trace) traceMsg(comp(), "insertbefore call to original\n");1250cfg()->insertBefore(callRecompileBlock, originalFirstBlock);12511252if (trace) traceMsg(comp(), "remove start to original\n");1253cfg()->removeEdge(cfg()->getStart(), originalFirstBlock);1254if (trace) traceMsg(comp(), "set first\n");1255_methodSymbol->setFirstTreeTop(guardBlock->getEntry());12561257comp()->getRecompilationInfo()->getJittedBodyInfo()->setUsesGCR();1258}12591260void1261TR_J9ByteCodeIlGenerator::createGeneratedFirstBlock()1262{1263_block = TR::Block::createEmptyBlock(comp());1264cfg()->addNode(_block);1265cfg()->addEdge(cfg()->getStart(), _block);1266cfg()->addEdge(_block, cfg()->getEnd());1267_methodSymbol->setFirstTreeTop(_block->getEntry());1268}12691270bool1271TR_J9ByteCodeIlGenerator::hasFPU()1272{1273bool result = !comp()->getOption(TR_DisableFPCodeGen) ? comp()->target().cpu.hasFPU() : false;1274return result;1275}127612771278bool1279TR_J9ByteCodeIlGenerator::genJNIIL()1280{1281if (!cg()->getSupportsDirectJNICalls() || comp()->getOption(TR_DisableDirectToJNI) || (comp()->compileRelocatableCode() && !cg()->supportsDirectJNICallsForAOT()))1282return false;12831284// A JNI thunk method cannot call back to the slow path, as would occur in the following case1285if (method()->numberOfParameterSlots() > J9_INLINE_JNI_MAX_ARG_COUNT && comp()->cg()->hasFixedFrameC_CallingConvention())1286return false;12871288if (_methodSymbol->getRecognizedMethod() == TR::sun_misc_Unsafe_ensureClassInitialized)1289{1290return false;1291}129212931294bool HasFPU = hasFPU();1295#if defined(__ARM_PCS_VFP)1296HasFPU = false;1297#endif12981299if (!HasFPU && (method()->returnOpCode() == TR::freturn || method()->returnOpCode() == TR::dreturn))1300return false;13011302if (!HasFPU)1303{1304for (uint32_t i = 0; i < method()->numberOfParameterSlots(); ++i)1305{1306if (method()->parmType(i) == TR::Float || method()->parmType(i) == TR::Double)1307return false;1308}1309}13101311if (debug("traceInfo"))1312diagnostic("Compiling JNI virtual thunk for %s.\n", method()->signature(trMemory()));13131314createGeneratedFirstBlock();13151316_methodSymbol->setJNI();13171318ListIterator<TR::ParameterSymbol> parms(&_methodSymbol->getParameterList());1319for (TR::ParameterSymbol * p = parms.getFirst(); p; p = parms.getNext())1320loadAuto(p->getDataType(), p->getSlot());13211322TR::MethodSymbol::Kinds callKind = method()->isStatic() ? TR::MethodSymbol::Static : TR::MethodSymbol::Virtual;13231324TR::SymbolReference * callSymRef =1325symRefTab()->findOrCreateMethodSymbol(_methodSymbol->getResolvedMethodIndex(), -1, method(), callKind);13261327genInvokeDirect(callSymRef);13281329bool genMonitors = _methodSymbol->isSynchronised();13301331genReturn(method()->returnOpCode(), genMonitors);13321333prependEntryCode(_block);13341335return true;1336}13371338void1339TR_J9ByteCodeIlGenerator::genHWOptimizedStrProcessingAvailable()1340{1341static int32_t constToLoad = -1;1342initialize();1343int32_t firstIndex = _bcIndex;1344setIsGenerated(_bcIndex);1345if (constToLoad == -1)1346{1347if (cg()->getSupportsInlineStringCaseConversion())1348constToLoad = 1;1349else1350constToLoad = 0;1351}13521353loadConstant(TR::iconst, constToLoad);13541355setIsGenerated(++_bcIndex);1356_bcIndex = genReturn(method()->returnOpCode(), method()->isSynchronized());1357TR::Block * block = blocks(firstIndex);1358cfg()->addEdge(cfg()->getStart(), block);1359block->setVisitCount(_blockAddedVisitCount);1360block->getExit()->getNode()->copyByteCodeInfo(block->getLastRealTreeTop()->getNode());1361cfg()->insertBefore(block, 0);1362_bcIndex = 0;1363_methodSymbol->setFirstTreeTop(blocks(0)->getEntry());1364prependEntryCode(blocks(0));13651366dumpOptDetails(comp(), "\tOverriding default return value with %d.\n", constToLoad);1367}13681369void1370TR_J9ByteCodeIlGenerator::genJITIntrinsicsEnabled()1371{1372bool isZLinux = comp()->target().cpu.isZ() && comp()->target().isLinux();13731374static int32_t constToLoad = (comp()->target().isZOS() || isZLinux) &&1375!comp()->getOption(TR_DisablePackedDecimalIntrinsics) ? 1 : 0;13761377initialize();1378int32_t firstIndex = _bcIndex;1379setIsGenerated(_bcIndex);13801381loadConstant(TR::iconst, constToLoad);13821383setIsGenerated(++_bcIndex);1384_bcIndex = genReturn(method()->returnOpCode(), method()->isSynchronized());1385TR::Block * block = blocks(firstIndex);1386cfg()->addEdge(cfg()->getStart(), block);1387block->setVisitCount(_blockAddedVisitCount);1388block->getExit()->getNode()->copyByteCodeInfo(block->getLastRealTreeTop()->getNode());1389cfg()->insertBefore(block, 0);1390_bcIndex = 0;1391_methodSymbol->setFirstTreeTop(blocks(0)->getEntry());1392prependEntryCode(blocks(0));13931394dumpOptDetails(comp(), "\tOverriding default return value with %d.\n", constToLoad);1395}13961397void1398TR_J9ByteCodeIlGenerator::genIsORBDeepCopyAvailable()1399{1400static int32_t constToLoad = 1;1401initialize();1402int32_t firstIndex = _bcIndex;1403setIsGenerated(_bcIndex);14041405loadConstant(TR::iconst, constToLoad);14061407setIsGenerated(++_bcIndex);1408_bcIndex = genReturn(method()->returnOpCode(), method()->isSynchronized());1409TR::Block * block = blocks(firstIndex);1410cfg()->addEdge(cfg()->getStart(), block);1411block->setVisitCount(_blockAddedVisitCount);1412block->getExit()->getNode()->copyByteCodeInfo(block->getLastRealTreeTop()->getNode());1413cfg()->insertBefore(block, 0);1414_bcIndex = 0;1415_methodSymbol->setFirstTreeTop(blocks(0)->getEntry());1416prependEntryCode(blocks(0));14171418dumpOptDetails(comp(), "\tOverriding default return value with %d.\n", constToLoad);1419}142014211422void1423TR_J9ByteCodeIlGenerator::genJavaLangSystemIdentityHashCode()1424{1425TR::Block * ifBlock, * return0Block, * computeBlock;14261427//printf("Transforming TR::java_lang_System_identityHashCode in %s\n", comp()->signature());14281429// the object parameter1430ListIterator<TR::ParameterSymbol> parms(&_methodSymbol->getParameterList());1431TR::ParameterSymbol * p = parms.getFirst();1432TR::Node * objectRef = TR::Node::createLoad(symRefTab()->findOrCreateAutoSymbol(_methodSymbol, p->getSlot(), p->getDataType()));14331434// ifblock1435_block = ifBlock = TR::Block::createEmptyBlock(comp());1436_methodSymbol->setFirstTreeTop(ifBlock->getEntry());14371438loadAuto(p->getDataType(),p->getSlot());1439loadConstant(TR::aconst, 0);1440TR::Node * second = pop();1441TR::Node * first = pop();14421443computeBlock = TR::Block::createEmptyBlock(comp());14441445genTreeTop(TR::Node::createif(TR::ifacmpne, first, second, computeBlock->getEntry()));14461447// return0 block1448_block = return0Block = TR::Block::createEmptyBlock(comp());1449loadConstant(TR::iconst, 0);1450genTreeTop(TR::Node::create(method()->returnOpCode(), 1, pop()));14511452// compute block1453_block = computeBlock;14541455TR::Node *objHeaderFlagsField;1456TR::Node *opNode;1457TR::Node *constNode;1458TR::Node *shlNode;1459TR::Node *orNode;1460TR::SymbolReferenceTable *symRefTab = comp()->getSymRefTab();14611462// object header flags now occupy 4bytes (instead of 8) on 64-bit1463//1464objHeaderFlagsField = TR::Node::createWithSymRef(TR::iloadi, 1, 1, objectRef,1465symRefTab->findOrCreateHeaderFlagsSymbolRef());1466opNode = TR::Node::create(TR::ishr, 2, objHeaderFlagsField, TR::Node::create(objHeaderFlagsField,1467TR::iconst, 0, 16));14681469opNode = TR::Node::create(TR::iand, 2, opNode, TR::Node::create(opNode, TR::iconst, 0, 32767));1470shlNode = TR::Node::create(TR::ishl, 2, opNode, TR::Node::create(opNode, TR::iconst, 0, 16));14711472orNode = TR::Node::create(TR::ior, 2, opNode, shlNode);14731474TR::Node *trTreeTopNode = TR::Node::create(TR::treetop, 1, orNode);14751476computeBlock->append(TR::TreeTop::create(comp(), trTreeTopNode));14771478push(orNode);1479genTreeTop(TR::Node::create(method()->returnOpCode(), 1, pop()));14801481cfg()->addEdge(cfg()->getStart(), ifBlock);14821483cfg()->insertBefore(ifBlock, return0Block);1484cfg()->insertBefore(return0Block, computeBlock);1485cfg()->insertBefore(computeBlock, 0);1486}14871488bool1489TR_J9ByteCodeIlGenerator::genNewInstanceImplThunk()1490{1491// Answers a new instance of the class represented by the1492// receiver, created by invoking the default (i.e. zero-argument)1493// constructor. If there is no such constructor, or if the1494// creation fails (either because of a lack of available memory or1495// because an exception is thrown by the constructor), an1496// InstantiationException is thrown. If the default constructor1497// exists, but is not accessible from the context where this1498// message is sent, an IllegalAccessException is thrown.1499//1500if (debug("traceInfo"))1501diagnostic("Compiling newInstanceImpl thunk: %s.\n", method()->signature(trMemory()));15021503if (comp()->getRecompilationInfo())1504{1505comp()->getRecompilationInfo()->preventRecompilation();15061507// Disable Sampling1508TR_PersistentJittedBodyInfo *bodyInfo = comp()->getRecompilationInfo()->getJittedBodyInfo();1509if (bodyInfo)1510bodyInfo->setDisableSampling(true);1511}15121513TR_OpaqueClassBlock *classId = method()->classOfMethod(); // will never be java.lang.Class (unless we are in a hacky world, e.g. JarTester?)15141515TR_ResolvedMethod *ctor = fej9()->getDefaultConstructor(trMemory(), classId);1516if (!ctor || TR::Compiler->cls.isAbstractClass(comp(), classId)) return false;15171518TR::Block * firstBlock, * initBlock, * catchAllBlock;15191520_block = firstBlock = TR::Block::createEmptyBlock(comp());1521cfg()->addEdge(cfg()->getStart(), firstBlock);1522_methodSymbol->setFirstTreeTop(firstBlock->getEntry());15231524ListIterator<TR::ParameterSymbol> parms(&_methodSymbol->getParameterList());1525TR::ParameterSymbol *p0 = parms.getFirst();// this class1526TR::ParameterSymbol *p1 = parms.getNext(); // caller class15271528// HACK HACK HACK1529p0->setReferencedParameter();15301531if (!((TR_J9VM *)fej9())->isPublicClass(classId) || !ctor->isPublic())1532{1533TR::SymbolReference * accessCheckSymRef =1534symRefTab()->findOrCreateRuntimeHelper(TR_newInstanceImplAccessCheck, true, true, true);15351536loadConstant(TR::aconst, ctor->getPersistentIdentifier()); // Nullary Constructor's identifier1537loadAuto(p1->getDataType(), p1->getSlot()); // Caller Class1538//the call to findOrCreateClassSymbol is safe even though we pass CPI of -1 since it is guarded by !isAOT check in createResolvedMethodWithSignature1539loadSymbol(TR::loadaddr, symRefTab()->findOrCreateClassSymbol(_methodSymbol, -1, classId)); // This Class15401541TR::Node* node = pop();1542node = TR::Node::createWithSymRef(TR::aloadi, 1, 1, node, symRefTab()->findOrCreateJavaLangClassFromClassSymbolRef());1543push(node);15441545genTreeTop(genNodeAndPopChildren(TR::call, 3, accessCheckSymRef));1546}1547//the call to findOrCreateClassSymbol is safe even though we pass CPI of -1 since it is guarded by !isAOT check in createResolvedMethodWithSignature1548loadSymbol(TR::loadaddr, symRefTab()->findOrCreateClassSymbol(_methodSymbol, -1, classId));1549genNew();1550TR::SymbolReference * tempSymRef = symRefTab()->findOrCreatePendingPushTemporary(_methodSymbol, 0, TR::Address);1551genTreeTop(TR::Node::createStore(tempSymRef, pop()));15521553_block = initBlock = TR::Block::createEmptyBlock(comp());15541555push(TR::Node::createLoad(tempSymRef));1556dup();1557genInvokeDirect(symRefTab()->findOrCreateMethodSymbol(JITTED_METHOD_INDEX, -1, ctor, TR::MethodSymbol::Special));1558_methodSymbol->setMayHaveInlineableCall(true);1559genTreeTop(TR::Node::create(method()->returnOpCode(), 1, pop()));15601561cfg()->insertBefore(firstBlock, initBlock);1562cfg()->insertBefore(initBlock, 0);15631564return true;1565}15661567TR::Node *1568TR_J9ByteCodeIlGenerator::genNewInstanceImplCall(TR::Node *classNode)1569{1570TR_ASSERT(_methodSymbol->getRecognizedMethod() == TR::java_lang_Class_newInstance,1571"should only be finding a call to newInstanceImpl from newInstance");1572TR_ResolvedMethod *caller = method()->owningMethod(); // the caller of Class.newInstance()1573TR_ASSERT(caller, "should only be transforming newInstanceImpl call if newInstance is being inlined");15741575TR::Node *classNodeAsClass = TR::Node::createWithSymRef(TR::aloadi, 1, 1, classNode, symRefTab()->findOrCreateClassFromJavaLangClassSymbolRef());1576//the call to findOrCreateClassSymbol is safe even though we pass CPI of -1 since we check for !compileRelocatableCode() in the caller1577TR::Node *node = TR::Node::createWithSymRef(TR::loadaddr, 0, symRefTab()->findOrCreateClassSymbol(_methodSymbol, -1, caller->classOfMethod()));1578TR::Node *nodeAsObject = TR::Node::createWithSymRef(TR::aloadi, 1, 1, node, symRefTab()->findOrCreateJavaLangClassFromClassSymbolRef());15791580TR::Node *callNode = TR::Node::createWithSymRef(TR::acalli, 3, 3,1581classNodeAsClass,1582classNode,1583nodeAsObject,1584symRefTab()->findOrCreateObjectNewInstanceImplSymbol(_methodSymbol));15851586return callNode;1587}15881589void1590TR_J9ByteCodeIlGenerator::genDLTransfer(TR::Block *firstBlock)1591{1592TR::Block *newFirstBlock;1593IndexPair *innermostPair = NULL, *outmostPair = NULL, *ip;1594TR::SymbolReference *dltSteerSymRef = NULL;1595TR::TreeTop *steerTarget, *storeDltSteer = NULL;1596int32_t dltBCIndex = comp()->getDltBcIndex(), nestedCnt = 0;15971598// if we've DLTed into a non-empty object constructor (an evil bytecode modifier may have caused this),1599// then we will be broken because the we have not initialized the temp slot to use in the1600// call to jitCheckIfFinalize. in most cases this should be a non-issue because we almost always1601// inline Object.<init>1602//1603if (_methodSymbol->getResolvedMethod()->isNonEmptyObjectConstructor())1604{1605comp()->failCompilation<TR::ILGenFailure>("DLT into a non-empty Object constructor");1606}16071608for (ip = _backwardBranches.getFirst(); ip; ip = ip->getNext())1609{1610if (ip->_toIndex>dltBCIndex || ip->_fromIndex<dltBCIndex)1611continue;1612nestedCnt++;1613if (innermostPair == NULL)1614innermostPair = ip;1615outmostPair = ip;1616}16171618// if we are not within loops or we start the only loop, we can jump to the particular bytecode directly1619if (nestedCnt>1 || (innermostPair!=NULL && dltBCIndex!=innermostPair->_toIndex))1620{1621dltSteerSymRef = symRefTab()->createTemporary(comp()->getMethodSymbol(), TR::Int32);16221623TR::Node *storeNode = TR::Node::createWithSymRef(TR::istore, 1, 1, TR::Node::create(TR::iconst, 0, 0), dltSteerSymRef);1624storeDltSteer = TR::TreeTop::create(comp(), storeNode);1625}16261627// usually we should be at block starting point, but deal with middle of block anyway1628if (_blocks[dltBCIndex] != NULL)1629{1630if (dltSteerSymRef != NULL)1631_blocks[dltBCIndex]->prepend(storeDltSteer);1632steerTarget = _blocks[dltBCIndex]->getEntry();1633}1634else1635{1636TR::Block *myBlock = NULL;1637for (int32_t i=dltBCIndex-1; i>=0 && (myBlock=_blocks[i])==NULL; i--)1638;1639TR_ASSERT(myBlock!=NULL, "Cannot find the block DLT point belongs to");16401641for (steerTarget=myBlock->getEntry(); steerTarget!=myBlock->getExit() && steerTarget->getNode()->getByteCodeIndex()!=dltBCIndex; steerTarget=steerTarget->getNextTreeTop())1642;1643TR_ASSERT(steerTarget->getNode()->getByteCodeIndex()==dltBCIndex, "Cannot find the treeTop DLT point belongs to");16441645if (steerTarget == myBlock->getEntry())1646{1647if (dltSteerSymRef != NULL)1648myBlock->prepend(storeDltSteer);1649}1650else1651{1652// FIXME: fixupCommoning or copyExceptionSuccessor need to be revisited1653myBlock = myBlock->split(steerTarget, cfg());1654if (dltSteerSymRef != NULL)1655myBlock->prepend(storeDltSteer);1656steerTarget = myBlock->getEntry();1657}1658}16591660TR::TreeTop **haveSeenTargets = (TR::TreeTop **)comp()->trMemory()->allocateMemory(sizeof(void *) * (nestedCnt+1), heapAlloc);1661haveSeenTargets[0] = steerTarget;1662int32_t haveSeenCount = 1;1663for (; innermostPair != NULL && innermostPair != outmostPair->getNext(); innermostPair = innermostPair->getNext())1664{1665if (innermostPair->_fromIndex < dltBCIndex || innermostPair->_toIndex > dltBCIndex)1666continue;1667TR::Block *loopStart = _blocks[innermostPair->_toIndex];1668TR::TreeTop *entryTP = loopStart->getEntry();1669int32_t seenIndex;16701671// Handle multiple loops having the same _toIndex1672for (seenIndex=0; seenIndex < haveSeenCount && entryTP != haveSeenTargets[seenIndex]; seenIndex++);1673if (seenIndex < haveSeenCount)1674continue;1675loopStart->split(entryTP->getNextTreeTop(), cfg());1676TR::Node *childNode = TR::Node::createWithSymRef(TR::iload, 0, dltSteerSymRef);1677TR::Node *constNode = TR::Node::create(TR::iconst, 0, 0);1678TR::Node *ifNode = TR::Node::createif(TR::ificmpne, childNode, constNode, steerTarget);1679loopStart->prepend(TR::TreeTop::create(comp(), ifNode));1680cfg()->addEdge(loopStart, steerTarget->getNode()->getBlock());1681steerTarget = entryTP;1682haveSeenTargets[haveSeenCount++] = steerTarget;1683}16841685// Transfer the data in1686comp()->setDltSlotDescription(fej9()->getCurrentLocalsMapForDLT(comp()));1687newFirstBlock = _methodSymbol->prependEmptyFirstBlock();16881689if (dltSteerSymRef != NULL)1690{1691TR::Node *storeNode = TR::Node::createWithSymRef(TR::istore, 1, 1, TR::Node::create(TR::iconst, 0, 1), dltSteerSymRef);1692storeDltSteer = TR::TreeTop::create(comp(), storeNode);1693newFirstBlock->append(storeDltSteer);1694}16951696bool isSyncMethod=_methodSymbol->isSynchronised(), isStaticMethod=_methodSymbol->isStatic();1697int32_t tempSlots = _method->numberOfTemps();1698int32_t parmSlots = _method->numberOfParameterSlots();1699int32_t *slotsDescription = comp()->getDltSlotDescription();1700int32_t parmIteratorIdx = 0;1701TR::SymbolReference *shadowSymRef = symRefTab()->findOrCreateGenericIntShadowSymbolReference(0);1702TR::Node *dltBufChild = NULL;17031704symRefTab()->aliasBuilder.gcSafePointSymRefNumbers().set(shadowSymRef->getReferenceNumber());17051706if (parmSlots != 0 || tempSlots != 0 || (isSyncMethod && !isStaticMethod))1707{1708int32_t fixedOffset;17091710dltBufChild = TR::Node::createWithSymRef(TR::loadaddr, 0, symRefTab()->findOrCreateDLTBlockSymbolRef());17111712fixedOffset = fej9()->getDLTBufferOffsetInBlock();1713if (comp()->target().is64Bit())1714{1715TR::Node *constNode = TR::Node::create(TR::lconst, 0);1716constNode->setLongInt(fixedOffset);1717dltBufChild = TR::Node::create(TR::aladd, 2, dltBufChild, constNode);1718}1719else1720dltBufChild = TR::Node::create(TR::aiadd, 2, dltBufChild, TR::Node::create(TR::iconst, 0, fixedOffset));1721dltBufChild = TR::Node::createWithSymRef(TR::aloadi, 1, 1, dltBufChild, shadowSymRef);1722}17231724if (isSyncMethod && !isStaticMethod)1725{1726int32_t *first32Slots = slotsDescription;1727TR::SymbolReference *syncObjectSymRef = _methodSymbol->getSyncObjectTemp();1728bool slot0Modified = (syncObjectSymRef!=NULL);1729bool slot0StillActive = (*first32Slots) & 1;17301731parmIteratorIdx = 1;17321733// We have 4 scenarios to deal with:1734// slot0StillActive: no matter if slot0Modified or not, we cannot touch slot0 itself.1735// By and large, these should account for the majority cases for DLT.1736// There is no difference from normal JIT in these cases;1737// For modified case, we need to refresh the syncObjectTemp;1738// slot0 not active and notModified either:1739// This is the most likely error scenario we can encounter. For exception1740// handling purpose, we have to reinstate slot0, and we cannot go wrong.1741// slot0 not active but modified:1742// We cannot do much about it until METADATA can carry the receiver info1743// back to the exception handler. For now, we just bail out of the compilation.1744//17451746if (!slot0StillActive && slot0Modified)1747{1748comp()->failCompilation<TR::ILGenFailure>("DLT on a tampered method, need better MetaData to deal with it");1749}17501751// the syncObjectTemp cannot be relied on anymore, since its store is by-passed1752// Copy the hidden slot to our syncObjectTemp1753//1754TR::Node *loadHiddenSlot = NULL;1755if (slot0Modified)1756{1757loadHiddenSlot = TR::Node::createWithSymRef(TR::aloadi, 1, 1, dltBufChild, shadowSymRef);17581759TR::Node *storeSyncObject = TR::Node::createWithSymRef(TR::astore, 1, 1, loadHiddenSlot, syncObjectSymRef);1760newFirstBlock->append(TR::TreeTop::create(comp(), storeSyncObject));1761}17621763if (!slot0StillActive && !slot0Modified)1764{1765List<TR::SymbolReference> &slot0list = _methodSymbol->getAutoSymRefs(0);1766ListIterator<TR::SymbolReference> s0i(&slot0list);1767TR::SymbolReference *slot0SymRef = s0i.getFirst();17681769TR_ASSERT(slot0list.isSingleton(), "Unexpected use of slot 0");1770TR_ASSERT(slot0SymRef->getSymbol()->getDataType() == TR::Address, "This is not an address type");17711772if (loadHiddenSlot == NULL)1773loadHiddenSlot = TR::Node::createWithSymRef(TR::aloadi, 1, 1, dltBufChild, shadowSymRef);17741775// Reinstate slot01776*first32Slots |= 1;17771778// Defect 121354: this store cannot be eliminated, since stackWalker needs it.1779slot0SymRef->getSymbol()->setReinstatedReceiver();1780TR::Node *storeSlot0 = TR::Node::createWithSymRef(TR::astore, 1, 1, loadHiddenSlot, slot0SymRef);1781newFirstBlock->append(TR::TreeTop::create(comp(), storeSlot0));1782}1783}17841785// Defect 131382: we need to make sure parameter GC map right for dead parameters revived by JIT1786for (; parmIteratorIdx<parmSlots; parmIteratorIdx++)1787{1788List<TR::SymbolReference> &slotlist = _methodSymbol->getAutoSymRefs(parmIteratorIdx);1789ListIterator<TR::SymbolReference> si(&slotlist);1790TR::SymbolReference *parmSymRef = si.getFirst(), *slotSymRef;1791TR::ParameterSymbol *parmSym = NULL;1792int32_t *currentSlots = slotsDescription + (parmIteratorIdx/32);1793TR::Node *addrNode = NULL;1794int32_t nodeRealOffset = -1;17951796for (; parmSymRef; parmSymRef = si.getNext())1797{1798parmSym = parmSymRef->getSymbol()->getParmSymbol();1799if (parmSym)1800break;1801}18021803si.reset();1804slotSymRef = si.getFirst();18051806bool OSlotParm = (*currentSlots) & (1<<(parmIteratorIdx%32));18071808for (; slotSymRef; slotSymRef = si.getNext())1809{1810if (slotSymRef != parmSymRef)1811{1812TR::Node *loadNode, *storeNode;1813TR::DataType dataType = slotSymRef->getSymbol()->getDataType();1814bool zeroIt = ((OSlotParm && dataType!=TR::Address) ||1815(!OSlotParm && dataType==TR::Address));18161817TR_ASSERT(slotSymRef->getSymbol()->getParmSymbol()==NULL, "Multiple parms on the same slot");1818if (!zeroIt)1819{1820int32_t realOffset = (tempSlots+parmSlots-parmIteratorIdx-1) * TR::Compiler->om.sizeofReferenceAddress();18211822if (isSyncMethod)1823realOffset += TR::Compiler->om.sizeofReferenceAddress();18241825if (TR::Symbol::convertTypeToNumberOfSlots(dataType) == 2)1826{1827TR_ASSERT(parmIteratorIdx!=tempSlots+parmSlots-1, "Access beyond the temp buffer");1828realOffset -= TR::Compiler->om.sizeofReferenceAddress();1829}18301831if (addrNode==NULL || nodeRealOffset!=realOffset)1832{1833nodeRealOffset = realOffset;1834if (comp()->target().is64Bit())1835{1836TR::Node *constNode = TR::Node::create(TR::lconst, 0);1837constNode->setLongInt(realOffset);1838addrNode = TR::Node::create(TR::aladd, 2, dltBufChild, constNode);1839}1840else1841addrNode = TR::Node::create(TR::aiadd, 2, dltBufChild, TR::Node::create(TR::iconst, 0, realOffset));1842}1843loadNode = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectLoad(dataType), 1, 1, addrNode, shadowSymRef);1844}1845else1846{1847switch (dataType)1848{1849case TR::Int32:1850loadNode = TR::Node::iconst(0);1851break;18521853case TR::Int64:1854loadNode = TR::Node::lconst(0);1855break;18561857case TR::Address:1858loadNode = TR::Node::aconst(0);1859break;18601861case TR::Float:1862loadNode = TR::Node::create(TR::fconst, 0);1863loadNode->setFloat(0.0);1864break;18651866case TR::Double:1867loadNode = TR::Node::create(TR::dconst, 0);1868loadNode->setDouble(0.0);1869break;18701871default:1872TR_ASSERT(false, "Unexpected auto slot data type");1873loadNode = TR::Node::iconst(0);1874break;1875}1876}1877storeNode = TR::Node::createWithSymRef(comp()->il.opCodeForDirectStore(dataType), 1, 1, loadNode, slotSymRef);1878newFirstBlock->append(TR::TreeTop::create(comp(), storeNode));1879}1880}18811882if (parmSymRef && parmSym->isReferencedParameter() && parmSym->isCollectedReference() && !OSlotParm)1883{1884*currentSlots |= 1<<(parmIteratorIdx%32);1885parmSym->setReinstatedReceiver();1886TR::Node *resetNode = TR::Node::createWithSymRef(TR::astore, 1, 1, TR::Node::aconst(0), parmSymRef);1887newFirstBlock->append(TR::TreeTop::create(comp(), resetNode));1888}1889}18901891if (tempSlots != 0)1892{1893int32_t currentBundle, remainInBundle;18941895slotsDescription += parmSlots/32;1896currentBundle = *slotsDescription++;1897remainInBundle = 32 - parmSlots%32;1898if (remainInBundle != 32)1899currentBundle >>= (32 - remainInBundle);19001901for (int32_t i=0; i < tempSlots; i++)1902{1903TR::Node *addrNode = NULL;1904int32_t nodeRealOffset = -1;1905bool isOSlot = currentBundle & 1;19061907currentBundle >>= 1;1908remainInBundle -= 1;1909if (remainInBundle==0 && i!=tempSlots-1)1910{1911currentBundle = *slotsDescription++;1912remainInBundle = 32;1913}19141915List<TR::SymbolReference> &list = _methodSymbol->getAutoSymRefs(parmSlots+i);1916ListIterator<TR::SymbolReference> iterator(&list);1917TR::SymbolReference *symRef = iterator.getFirst();1918for (; symRef; symRef = iterator.getNext())1919{1920TR::Node *loadNode, *storeNode;1921TR::DataType dataType = symRef->getSymbol()->getDataType();1922bool zeroIt = ((isOSlot && dataType!=TR::Address) ||1923(!isOSlot && dataType==TR::Address));1924if (!zeroIt)1925{1926int32_t realOffset = (tempSlots-i-1) * TR::Compiler->om.sizeofReferenceAddress();19271928if (isSyncMethod)1929realOffset += TR::Compiler->om.sizeofReferenceAddress();19301931if (TR::Symbol::convertTypeToNumberOfSlots(dataType) == 2)1932{1933TR_ASSERT(i!=tempSlots-1, "Access beyond the temp buffer");1934realOffset -= TR::Compiler->om.sizeofReferenceAddress();1935}19361937if (addrNode==NULL || nodeRealOffset!=realOffset)1938{1939nodeRealOffset = realOffset;1940if (comp()->target().is64Bit())1941{1942TR::Node *constNode = TR::Node::create(TR::lconst, 0);1943constNode->setLongInt(realOffset);1944addrNode = TR::Node::create(TR::aladd, 2, dltBufChild, constNode);1945}1946else1947addrNode = TR::Node::create(TR::aiadd, 2, dltBufChild, TR::Node::create(TR::iconst, 0, realOffset));1948}1949loadNode = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectLoad(dataType), 1, 1, addrNode, shadowSymRef);1950}1951else1952{1953switch (dataType)1954{1955case TR::Int32:1956loadNode = TR::Node::iconst(0);1957break;19581959case TR::Int64:1960loadNode = TR::Node::lconst(0);1961break;19621963case TR::Address:1964loadNode = TR::Node::aconst(0);1965break;19661967case TR::Float:1968loadNode = TR::Node::create(TR::fconst, 0);1969loadNode->setFloat(0.0);1970break;19711972case TR::Double:1973loadNode = TR::Node::create(TR::dconst, 0);1974loadNode->setDouble(0.0);1975break;19761977default:1978TR_ASSERT(false, "Unexpected auto slot data type");1979loadNode = TR::Node::iconst(0);1980break;1981}1982}1983storeNode = TR::Node::createWithSymRef(comp()->il.opCodeForDirectStore(dataType), 1, 1, loadNode, symRef);1984newFirstBlock->append(TR::TreeTop::create(comp(), storeNode));1985}1986}1987}19881989for (auto nextSymRef = comp()->getMonitorAutoSymRefsInCompiledMethod()->begin(); nextSymRef != comp()->getMonitorAutoSymRefsInCompiledMethod()->end(); ++nextSymRef)1990{1991TR_ASSERT(!comp()->getOption(TR_MimicInterpreterFrameShape), "cannot initialize sync temp symRefs in DLT block when autos can alias each other\n");1992TR::Node *aconstNode = TR::Node::aconst(0);1993TR::Node *storeNode = TR::Node::createWithSymRef(TR::astore, 1, 1, aconstNode, *nextSymRef);1994storeNode->setLiveMonitorInitStore(true);1995newFirstBlock->append(TR::TreeTop::create(comp(), storeNode));1996}19971998newFirstBlock->append(TR::TreeTop::create(comp(), TR::Node::create(TR::Goto, 0, steerTarget)));1999if (firstBlock != steerTarget->getNode()->getBlock())2000{2001cfg()->addEdge(newFirstBlock, steerTarget->getNode()->getBlock());2002cfg()->removeEdge(newFirstBlock, firstBlock);2003}2004}20052006void2007TR_J9ByteCodeIlGenerator::inlineJitCheckIfFinalizeObject(TR::Block *firstBlock)2008{20092010///comp()->dumpMethodTrees("before inlineJitCheckIfFinalizeObject", _methodSymbol);2011TR::SymbolReference *finalizeSymRef = comp()->getSymRefTab()->findOrCreateRuntimeHelper(TR_jitCheckIfFinalizeObject, true, true, true);2012int32_t origNumBlocks = cfg()->getNextNodeNumber();20132014for (TR::Block *block = firstBlock; block; block = block->getNextBlock())2015{2016// ignore processing any new blocks created2017//2018if (block->getNumber() >= origNumBlocks)2019continue;20202021TR::TreeTop *tt = block->getEntry();2022for (; tt != block->getExit(); tt = tt->getNextTreeTop())2023{2024TR::Node *node = tt->getNode();2025if (node->getOpCodeValue() == TR::treetop)2026node = node->getFirstChild();20272028// look for2029// vcall jitCheckIfFinalizeObject2030// receiverArg2031//2032// if found, create a diamond control flow2033// if (classDepthAndFlags & FINALIZE)2034// vcall jitCheckIfFinalizeObject2035// else2036// remainder2037//2038bool is64bit = comp()->target().is64Bit();2039//2040if (node->getOpCode().isCall() &&2041(node->getSymbolReference() == finalizeSymRef))2042{2043TR::Node *vftLoad = TR::Node::createWithSymRef(TR::aloadi, 1, 1,2044node->getFirstChild(),2045comp()->getSymRefTab()->findOrCreateVftSymbolRef());20462047TR::ILOpCodes loadOp = is64bit ? TR::lloadi : TR::iloadi;20482049TR::Node *classDepthAndFlagsNode = TR::Node::createWithSymRef(loadOp, 1, 1,2050vftLoad,2051comp()->getSymRefTab()->findOrCreateClassAndDepthFlagsSymbolRef());2052TR::Node *andConstNode = TR::Node::create(classDepthAndFlagsNode, is64bit ? TR::lconst : TR::iconst, 0);2053if (is64bit)2054andConstNode->setLongInt(fej9()->getFlagValueForFinalizerCheck());2055else2056andConstNode->setInt(fej9()->getFlagValueForFinalizerCheck());20572058TR::Node *andNode = TR::Node::create(is64bit ? TR::land : TR::iand, 2, classDepthAndFlagsNode, andConstNode);2059TR::Node *constCheckNode = TR::Node::create(andConstNode, is64bit ? TR::lconst : TR::iconst, 0);2060if (is64bit)2061constCheckNode->setLongInt(0);2062else2063constCheckNode->setInt(0);2064TR::Node *cmp = TR::Node::createif(is64bit ? TR::iflcmpne : TR::ificmpne,2065andNode,2066constCheckNode,2067NULL);2068TR::TreeTop *cmpTree = TR::TreeTop::create(comp(), cmp);2069TR::Node *dupCallNode = tt->getNode()->duplicateTree();2070TR::TreeTop *dupCallTreeTop = TR::TreeTop::create(comp(), dupCallNode);2071block->createConditionalBlocksBeforeTree(tt, cmpTree, dupCallTreeTop, NULL, cfg(), false);2072// createConditionalBlocks sets the ifBlock as cold2073// reset the flag and setup the appropriate frequency here2074//2075TR::Block *callBlock = cmp->getBranchDestination()->getNode()->getBlock();2076callBlock->setIsCold(false);2077callBlock->setFrequency(MAX_COLD_BLOCK_COUNT+1);2078///comp()->dumpMethodTrees("after inlineJitCheckIfFinalizeObject", _methodSymbol);2079break;2080}2081}2082}2083}20842085//A structure to hold the names of all methods in DecimalFormatHelper that we need to replace with other2086//methods.2087struct TR_J9ByteCodeIlGenerator::methodRenamePair TR_J9ByteCodeIlGenerator::_decFormatRenames[_numDecFormatRenames] =2088{ {"com/ibm/jit/DecimalFormatHelper$FieldPosition.setBeginIndex(I)V", "java/text/FieldPosition.setBeginIndex(I)V"},2089{"com/ibm/jit/DecimalFormatHelper$FieldPosition.setEndIndex(I)V", "java/text/FieldPosition.setEndIndex(I)V"},2090{"com/ibm/jit/DecimalFormatHelper$FieldPosition.getFieldDelegate()Lcom/ibm/jit/DecimalFormatHelper$FieldDelegate;", "java/text/FieldPosition.getFieldDelegate()Ljava/text/Format$FieldDelegate;"},2091{"com/ibm/jit/DecimalFormatHelper$FieldPosition.getFieldAttribute()Ljava/text/Format$Field;", "java/text/FieldPosition.getFieldAttribute()Ljava/text/Format$Field;"},2092{"com/ibm/jit/DecimalFormatHelper$DigitList.isZero()Z", "java/text/DigitList.isZero()Z"},2093{"com/ibm/jit/DecimalFormatHelper$DigitList.set(ZJ)V", "java/text/DigitList.set(ZJ)V"},2094{"com/ibm/jit/DecimalFormatHelper.isGroupingUsed(Ljava/text/NumberFormat;)Z", "java/text/NumberFormat.isGroupingUsed()Z"},2095{"com/ibm/jit/DecimalFormatHelper.getBigDecimalMultiplier(Ljava/text/DecimalFormat;)Ljava/math/BigDecimal;", "java/text/DecimalFormat.getBigDecimalMultiplier()Ljava/math/BigDecimal;"},2096{"com/ibm/jit/DecimalFormatHelper.subformat(Ljava/text/DecimalFormat;Ljava/lang/StringBuffer;Lcom/ibm/jit/DecimalFormatHelper$FieldDelegate;ZZIIII)Ljava/lang/StringBuffer;", "java/text/DecimalFormat.subformat(Ljava/lang/StringBuffer;Ljava/text/Format$FieldDelegate;ZZIIII)Ljava/lang/StringBuffer;"},2097};20982099//Replaces all methods and fields in DecimalFormatHelper.format routine with appropriate methods and fields.2100//returns true if all methods and fields are replaced successfully2101bool TR_J9ByteCodeIlGenerator::replaceMembersOfFormat()2102{2103for (int i =0; i < _numDecFormatRenames; i++)2104{2105_decFormatRenamesDstSymRef[i] = fej9()->findOrCreateMethodSymRef(comp(), _methodSymbol, _decFormatRenames[i].dstMethodSignature);2106}21072108bool successful = true;2109for (TR::TreeTop* tt = _methodSymbol->getFirstTreeTop(); (tt != NULL); tt = tt->getNextRealTreeTop())2110{2111TR::Node *node = tt->getNode();2112if (node->getOpCodeValue() == TR::treetop)2113node = node->getFirstChild();2114TR::Node *callNode = node;2115if (!node->getOpCode().isCall() && (node->getNumChildren() > 0))2116callNode = node->getFirstChild();2117successful = successful && replaceMethods(tt, callNode);2118successful = successful && replaceFieldsAndStatics(tt, callNode);2119}2120return successful;2121}21222123bool TR_J9ByteCodeIlGenerator::replaceMethods(TR::TreeTop *tt, TR::Node *node)2124{2125if (!node->getOpCode().isCall() || !node->getOpCode().hasSymbolReference()) return true;2126if (node->getSymbolReference()->getSymbol()->castToMethodSymbol()->isHelper()) return true;2127TR::Method * method = node->getSymbolReference()->getSymbol()->castToMethodSymbol()->getMethod();2128//I use heapAlloc because this function is called many times for a small set of methods.2129const char* nodeName = method->signature(trMemory(), heapAlloc);2130for (int i = 0; i < _numDecFormatRenames; i++)2131{2132if (!strcmp(nodeName, _decFormatRenames[i].srcMethodSignature))2133{2134if (performTransformation(comp(), "%sreplaced %s by %s in [%p]\n",2135OPT_DETAILS, _decFormatRenames[i].srcMethodSignature, _decFormatRenames[i].dstMethodSignature, node))2136{2137if (_decFormatRenamesDstSymRef[i] == NULL)2138return false;2139node->setSymbolReference(_decFormatRenamesDstSymRef[i]);2140return true;2141}2142else2143{2144return false;2145}2146}2147}2148return true;2149}21502151static bool matchFieldOrStaticName(TR::Compilation* comp, TR::Node* node, char* staticOrFieldName) {2152if ((!node->getOpCode().isLoad() && !node->getOpCode().isStore()) ||2153!node->getOpCode().hasSymbolReference())2154return false;2155TR::SymbolReference* symRef = node->getSymbolReference();2156TR::Symbol* sym = symRef->getSymbol();2157if (sym == NULL || symRef->getCPIndex() < 0) return false;2158TR_ResolvedMethod* method = comp->getOwningMethodSymbol(symRef->getOwningMethodIndex())->getResolvedMethod();2159if (!method) return false;2160switch(sym->getKind()) {2161case TR::Symbol::IsStatic:2162{2163//make sure it's not a "helper" symbol2164int32_t index = symRef->getReferenceNumber();2165int32_t nonhelperIndex = comp->getSymRefTab()->getNonhelperIndex(comp->getSymRefTab()->getLastCommonNonhelperSymbol());2166int32_t numHelperSymbols = comp->getSymRefTab()->getNumHelperSymbols();2167if ((index < numHelperSymbols) || (index < nonhelperIndex) || !sym->isStaticField()) return false;21682169const char * nodeName = method->staticName(symRef->getCPIndex(), comp->trMemory(), stackAlloc);2170return !strcmp(nodeName, staticOrFieldName);2171}2172case TR::Symbol::IsShadow:2173{2174const char * nodeName = method->fieldName(symRef->getCPIndex(), comp->trMemory(), stackAlloc);2175return !strcmp(nodeName, staticOrFieldName);2176}2177default:2178return false;2179}2180}21812182bool TR_J9ByteCodeIlGenerator::replaceField(TR::Node* node, char* destClass,2183char* destFieldName, char* destFieldSignature,2184int parmIndex)2185{2186TR_OpaqueClassBlock *c = fej9()->getClassFromSignature(destClass, strlen(destClass), comp()->getCurrentMethod());2187//When, e.g., AOT is enabled, classes are not loaded at compile time so the2188//function above returns NULL2189if (c == NULL)2190return false;2191if (performTransformation(comp(), "%ssymref replaced by %s.%s %s in [%p]\n", OPT_DETAILS, destClass, destFieldName, destFieldSignature, node))2192{2193//The following code (up to and including the call to initShadowSymbol) has been adapted from2194//TR::SymbolReferenceTable::findOrCreateShadowSymbol2195uint32_t offset =2196fej9()->getInstanceFieldOffset(c, destFieldName, destFieldSignature) +2197fej9()->getObjectHeaderSizeInBytes();21982199TR::DataType type = node->getDataType();2200TR::Symbol * sym = TR::Symbol::createShadow(trHeapMemory(), type);2201sym->setPrivate();2202TR::SymbolReference* symRef =2203new (trHeapMemory()) TR::SymbolReference(comp()->getSymRefTab(), sym,2204comp()->getMethodSymbol()->getResolvedMethodIndex(),2205-1, 0);2206comp()->getSymRefTab()->checkUserField(symRef);2207//Is the last field (isUnresolvedInCP) set correctly ?2208comp()->getSymRefTab()->initShadowSymbol(comp()->getCurrentMethod(), symRef, true, type, offset, false);22092210//we need to change a field reference f to p.f where p is the first parameter (of class DecimalFormat)2211//so we need to make the load/store node an indirect one and add, as a child, an indirect load to load p2212if (!node->getOpCode().isIndirect())2213{2214if (node->getOpCode().isLoad())2215{2216TR::Node::recreate(node, comp()->il.opCodeForIndirectLoad(type));2217node->setNumChildren(1);2218}2219else2220{2221TR_ASSERT(node->getOpCode().isStore(), "node can be either a load or a store\n");2222TR::Node::recreate(node, comp()->il.opCodeForIndirectStore(type));2223node->setNumChildren(2);2224node->setChild(1, node->getChild(0));2225node->setChild(0, NULL);2226}2227ListIterator<TR::ParameterSymbol> parms(&_methodSymbol->getParameterList());2228TR_ASSERT(parmIndex == 0 || parmIndex == 1, "invalid parmIndex\n");2229TR::ParameterSymbol * p = parms.getFirst();2230if (parmIndex == 1)2231p = parms.getNext();2232TR::Node* decFormObjLoad = TR::Node::createLoad(node, symRefTab()->findOrCreateAutoSymbol(_methodSymbol, p->getSlot(), p->getDataType()));2233node->setAndIncChild(0, decFormObjLoad);2234}2235node->setSymbolReference(symRef);2236return true;2237}2238return false;2239}22402241bool TR_J9ByteCodeIlGenerator::replaceStatic(TR::Node* node,2242char* dstClassName, char* staticName, char* type)2243{2244TR_OpaqueClassBlock *c = fej9()->getClassFromSignature(dstClassName, strlen(dstClassName), comp()->getCurrentMethod());22452246// When, e.g., AOT is enabled, classes are not loaded at compile time so the2247// function above returns NULL2248//2249if (c == NULL)2250return false;22512252void* dataAddress = fej9()->getStaticFieldAddress(c, (unsigned char *) staticName, strlen(staticName),2253(unsigned char *) type, strlen(type));22542255if ( dataAddress != NULL &&2256!node->getSymbolReference()->isUnresolved() &&2257performTransformation(comp(), "%sreplaced %s.%s in [%p]\n", OPT_DETAILS, dstClassName, staticName, node)2258)2259{2260//I'm not setting the correct SymRef. I'm just changing the address2261((TR::StaticSymbol*)node->getSymbolReference()->getSymbol())->setStaticAddress(dataAddress);2262return true;2263}2264else2265return false;2266}226722682269bool TR_J9ByteCodeIlGenerator::replaceFieldsAndStatics(TR::TreeTop *tt, TR::Node *node) {2270bool result = true;2271if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.INSTANCE Lcom/ibm/jit/DecimalFormatHelper$FieldPosition;"))2272{2273//Replace static com/ibm/jit/DecimalFormatHelper.INSTANCE with static java/text/DontCareFieldPosition.INSTANCE2274result = replaceStatic(node, "java/text/DontCareFieldPosition", "INSTANCE", "Ljava/text/FieldPosition;");2275}2276else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.doubleDigitsTens [C"))2277{2278result = replaceStatic(node, "java/math/BigDecimal", "doubleDigitsTens", "[C");2279}2280else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.doubleDigitsOnes [C"))2281{2282result = replaceStatic(node, "java/math/BigDecimal", "doubleDigitsOnes", "[C");2283}2284else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.multiplier I"))2285{2286result = replaceField(node, "java/text/DecimalFormat", "multiplier", "I", 0);2287}2288else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.digitList Lcom/ibm/jit/DecimalFormatHelper$DigitList;"))2289{2290result = replaceField(node, "java/text/DecimalFormat", "digitList", "Ljava/text/DigitList;", 0);2291}2292else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper$DigitList.digits [C"))2293{2294result = replaceField(node, "java/text/DigitList", "digits", "[C", 0);2295}2296else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper$DigitList.decimalAt I"))2297{2298result = replaceField(node, "java/text/DigitList", "decimalAt", "I", 0);2299}2300else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper$DigitList.count I"))2301{2302result = replaceField(node, "java/text/DigitList", "count", "I", 0);2303}2304else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.flags I"))2305{2306result = replaceField(node, "java/math/BigDecimal", "flags", "I", 1);2307}2308else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.laside J"))2309{2310result = replaceField(node, "java/math/BigDecimal", "laside", "J", 1);2311}2312else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.scale I"))2313{2314//Use "scale" for java 6 or 626 and "cachedScale" for java 72315result = replaceField(node, "java/math/BigDecimal", "cachedScale", "I", 1);2316}2317else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.symbols Ljava/text/DecimalFormatSymbols;"))2318{2319result = replaceField(node, "java/text/DecimalFormat", "symbols", "Ljava/text/DecimalFormatSymbols;", 0);2320}2321else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.isCurrencyFormat Z"))2322{2323result = replaceField(node, "java/text/DecimalFormat", "isCurrencyFormat", "Z", 0);2324}2325else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.decimalSeparatorAlwaysShown Z"))2326{2327result = replaceField(node, "java/text/DecimalFormat", "decimalSeparatorAlwaysShown", "Z", 0);2328}2329else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.useExponentialNotation Z"))2330{2331result = replaceField(node, "java/text/DecimalFormat", "useExponentialNotation", "Z", 0);2332}2333else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.negativePrefix Ljava/lang/String;"))2334{2335result = replaceField(node, "java/text/DecimalFormat", "negativePrefix", "Ljava/lang/String;", 0);2336}2337else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.negativeSuffix Ljava/lang/String;"))2338{2339result = replaceField(node, "java/text/DecimalFormat", "negativeSuffix", "Ljava/lang/String;", 0);2340}2341else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.positivePrefix Ljava/lang/String;"))2342{2343result = replaceField(node, "java/text/DecimalFormat", "positivePrefix", "Ljava/lang/String;", 0);2344}2345else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.positiveSuffix Ljava/lang/String;"))2346{2347result = replaceField(node, "java/text/DecimalFormat", "positiveSuffix", "Ljava/lang/String;", 0);2348}2349else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.groupingSize B"))2350{2351result = replaceField(node, "java/text/DecimalFormat", "groupingSize", "B", 0);2352}2353else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.minExponentDigits B"))2354{2355result = replaceField(node, "java/text/DecimalFormat", "minExponentDigits", "B", 0);2356}2357for (int i = 0; i < node->getNumChildren(); i++) {2358result = result && replaceFieldsAndStatics(tt, node->getChild(i));2359}2360return result;2361}23622363/**2364* Expand a checkcast tree for an unresolved class.2365*2366* A ResolveCHK is emitted before the checkcast, and both the ResolveCHK and2367* checkcast are skipped when the object tested is null.2368*2369* Pictorially, transform this:2370*2371@verbatim2372+-<block_$orig>------------------------------+2373| ... $pre |2374| n1n checkcast |2375| n2n $obj |2376| n3n loadaddr $klass [unresolved Static] |2377| ... $post |2378+--------------------------------------------+2379@endverbatim2380*2381* into this:2382*2383@verbatim2384+-<block_$orig>------------------+2385| ... $pre |2386| ... treetop |2387| n2n $obj |2388| ... astore $tmp_obj |2389| n2n =>$obj |2390| ... (more fixupCommoning) |2391| ... ifacmpeq --> block_$merge |----------+2392| n2n =>$obj | |2393| ... aconst NULL | |2394+--------------------------------+ |2395| |2396fallthrough | |2397| |2398v |2399+-<block_$nonnull>---------------------------+ |2400| ... ResolveCHK | |2401| n3n loadaddr $klass [unresolved Static] | |2402| n1n checkcast | |2403| ... aload $tmp_obj | |2404| n3n =>loadaddr | |2405+--------------------------------------------+ |2406| |2407fallthrough | +-------------------+2408| |2409v v2410+-<block_$merge>--------------+2411| $post (w/ fixupCommoning) |2412+-----------------------------+2413@endverbatim2414*2415* @param tree The checkcast tree as generated by the walker2416*2417* @see genCheckCast(int32_t)2418* @see expandUnresolvedClassTypeTests(List<TR::TreeTop>*)2419*/2420void TR_J9ByteCodeIlGenerator::expandUnresolvedClassCheckcast(TR::TreeTop *tree)2421{2422TR::Node *checkcastNode = tree->getNode();2423TR_ASSERT(checkcastNode->getOpCodeValue() == TR::checkcast, "unresolved class checkcast: expected treetop %p node n%un to be checkcast but was %s\n", tree, checkcastNode->getGlobalIndex(), checkcastNode->getOpCode().getName());24242425TR::Node *objNode = checkcastNode->getFirstChild();2426TR::Node *classNode = checkcastNode->getSecondChild();2427TR_ASSERT(classNode->getOpCodeValue() == TR::loadaddr, "unresolved class checkcast n%un: expected class child n%un to be loadaddr but was %s\n", checkcastNode->getGlobalIndex(), classNode->getGlobalIndex(), classNode->getOpCode().getName());2428TR_ASSERT(classNode->getSymbolReference()->isUnresolved(), "unresolved class checkcast n%un: expected symref of class child n%un to be unresolved\n", checkcastNode->getGlobalIndex(), classNode->getGlobalIndex());2429TR_ASSERT(classNode->getReferenceCount() == 1, "unresolved class checkcast n%un: expected class child n%un to have reference count 1\n", checkcastNode->getGlobalIndex(), classNode->getGlobalIndex());24302431bool trace = comp()->getOption(TR_TraceILGen);2432if (trace)2433traceMsg(comp(), "expanding unresolved class checkcast n%un in block_%d\n", checkcastNode->getGlobalIndex(), tree->getEnclosingBlock()->getNumber());24342435TR::Node *objAnchor = TR::Node::create(TR::treetop, 1, objNode);2436objAnchor->copyByteCodeInfo(checkcastNode);2437tree->insertBefore(TR::TreeTop::create(comp(), objAnchor));24382439TR::Block *headBlock = tree->getEnclosingBlock();2440const bool fixupCommoning = true;2441TR::Block *nonNullCaseBlock = headBlock->split(tree, cfg(), fixupCommoning);2442TR::Block *tailBlock = nonNullCaseBlock->split(tree->getNextTreeTop(), cfg(), fixupCommoning);24432444headBlock->getExit()->getNode()->copyByteCodeInfo(checkcastNode);2445nonNullCaseBlock->getEntry()->getNode()->copyByteCodeInfo(checkcastNode);2446nonNullCaseBlock->getExit()->getNode()->copyByteCodeInfo(checkcastNode);2447tailBlock->getEntry()->getNode()->copyByteCodeInfo(checkcastNode);24482449TR::Node *aconstNull = TR::Node::aconst(0);2450TR::Node *nullTest = TR::Node::createif(TR::ifacmpeq, objNode, aconstNull, tailBlock->getEntry());2451aconstNull->copyByteCodeInfo(checkcastNode);2452nullTest->copyByteCodeInfo(checkcastNode);2453headBlock->append(TR::TreeTop::create(comp(), nullTest));2454cfg()->addEdge(headBlock, tailBlock);24552456TR_ASSERT(checkcastNode->getSecondChild() == classNode, "unresolved class checkcast n%un: split block should not have replaced class child n%un with n%un\n", checkcastNode->getGlobalIndex(), classNode->getGlobalIndex(), checkcastNode->getSecondChild()->getGlobalIndex());2457TR::Node *resolveCheckNode = genResolveCheck(classNode);2458resolveCheckNode->copyByteCodeInfo(checkcastNode);2459nonNullCaseBlock->prepend(TR::TreeTop::create(comp(), resolveCheckNode));24602461if (trace)2462traceMsg(comp(), "\tblock_%d: resolve, checkcast\n\tblock_%d: tail of original block\n", nonNullCaseBlock->getNumber(), tailBlock->getNumber());2463}24642465/**2466* Expand an instanceof tree for an unresolved class.2467*2468* A ResolveCHK is emitted before the instanceof, and both the ResolveCHK and2469* instanceof are skipped when the object tested is null. In that case, the2470* result is false. In the remainder of the block, occurrences of the original2471* instanceof node are made into occurrences of an iload of a new temp, into2472* which each of the conditional blocks stores the appropriate result.2473*2474* Pictorially, transform this:2475*2476@verbatim2477+-<block_$orig>---------------------------------+2478| ... $pre |2479| n1n treetop |2480| n2n instanceof |2481| n3n $obj |2482| n4n loadaddr $klass [unresolved Static] |2483| ... $post |2484+-----------------------------------------------+2485@endverbatim2486*2487* into this:2488*2489@verbatim2490+-<block_$orig>------------------+2491| ... $pre |2492| ... treetop |2493| n3n $obj |2494| ... astore $tmp_obj |2495| n3n =>$obj |2496| ... (more fixupCommoning) |2497| ... ifacmpeq --> block_$null |-----------------+2498| n3n =>$obj | |2499| ... aconst NULL | |2500+--------------------------------+ |2501| |2502fallthrough | |2503| |2504v |2505+-<block_$nonnull>-----------------------+ v2506| ResolveCHK | +-<block_$null>----------+2507| loadaddr $klass [unresolved Static] | | istore $tmp_result |2508| istore $tmp_result | | iconst 0 |2509| instanceof | | goto --> block_$merge |2510| aload $tmp_obj | +------------------------+2511| =>loadaddr | |2512+----------------------------------------+ |2513| |2514fallthrough | +--------------------------+2515| |2516v v2517+-<block_$merge>-----------------+2518| n1n treetop |2519| n2n iload $tmp_result |2520| ... $post (w/ fixupCommoning) |2521+--------------------------------+2522@endverbatim2523*2524* except that the treetop n1n is removed from the merge block, because it's2525* clearly unnecessary.2526*2527* @param tree The instanceof tree as generated by the walker2528*2529* @see genInstanceof(int32_t)2530* @see expandUnresolvedClassTypeTests(List<TR::TreeTop>*)2531*/2532void TR_J9ByteCodeIlGenerator::expandUnresolvedClassInstanceof(TR::TreeTop *tree)2533{2534TR::Node *treetopNode = tree->getNode();2535TR_ASSERT(treetopNode->getOpCodeValue() == TR::treetop, "unresolved class instanceof: expected treetop %p node n%un to be treetop but was %s\n", tree, treetopNode->getGlobalIndex(), treetopNode->getOpCode().getName());25362537TR::Node *instanceofNode = treetopNode->getFirstChild();2538TR_ASSERT(instanceofNode->getOpCodeValue() == TR::instanceof, "unresolved class instanceof: expected treetop %p node n%un child n%un to be instanceof but was %s\n", tree, treetopNode->getGlobalIndex(), instanceofNode->getGlobalIndex(), instanceofNode->getOpCode().getName());25392540TR::Node *objNode = instanceofNode->getFirstChild();2541TR::Node *origClassNode = instanceofNode->getSecondChild();2542TR_ASSERT(origClassNode->getOpCodeValue() == TR::loadaddr, "unresolved class instanceof n%un: expected class child n%un to be loadaddr but was %s\n", instanceofNode->getGlobalIndex(), origClassNode->getGlobalIndex(), origClassNode->getOpCode().getName());2543TR_ASSERT(origClassNode->getSymbolReference()->isUnresolved(), "unresolved class instanceof n%un: expected symref of class child n%un to be unresolved\n", instanceofNode->getGlobalIndex(), origClassNode->getGlobalIndex());25442545bool trace = comp()->getOption(TR_TraceILGen);2546if (trace)2547traceMsg(comp(), "expanding unresolved class instanceof n%un in block_%d\n", instanceofNode->getGlobalIndex(), tree->getEnclosingBlock()->getNumber());25482549TR::Node *objAnchor = TR::Node::create(TR::treetop, 1, objNode);2550objAnchor->copyByteCodeInfo(instanceofNode);2551tree->insertBefore(TR::TreeTop::create(comp(), objAnchor));25522553// create blocks2554TR::Block *headBlock = tree->getEnclosingBlock();2555const bool fixupCommoning = true;2556TR::Block *nonNullCaseBlock = headBlock->split(tree, cfg(), fixupCommoning);2557TR::Block *tailBlock = nonNullCaseBlock->split(tree, cfg(), fixupCommoning);2558TR::Block *nullCaseBlock = TR::Block::createEmptyBlock(comp());2559cfg()->addNode(nullCaseBlock);2560cfg()->findLastTreeTop()->join(nullCaseBlock->getEntry());25612562headBlock->getExit()->getNode()->copyByteCodeInfo(instanceofNode);2563nonNullCaseBlock->getEntry()->getNode()->copyByteCodeInfo(instanceofNode);2564nonNullCaseBlock->getExit()->getNode()->copyByteCodeInfo(instanceofNode);2565nullCaseBlock->getEntry()->getNode()->copyByteCodeInfo(instanceofNode);2566nullCaseBlock->getExit()->getNode()->copyByteCodeInfo(instanceofNode);2567tailBlock->getEntry()->getNode()->copyByteCodeInfo(instanceofNode);25682569// headBlock ends with a null test conditionally jumping to nullCaseBlock2570TR::Node *aconstNull = TR::Node::aconst(0);2571TR::Node *nullTest = TR::Node::createif(TR::ifacmpeq, objNode, aconstNull, nullCaseBlock->getEntry());2572aconstNull->copyByteCodeInfo(instanceofNode);2573nullTest->copyByteCodeInfo(instanceofNode);2574headBlock->append(TR::TreeTop::create(comp(), nullTest));2575cfg()->addEdge(headBlock, nullCaseBlock);25762577// New temporary for the result of instanceof.2578TR::SymbolReference *resultTemp = symRefTab()->createTemporary(_methodSymbol, TR::Int32);25792580// In the null case, instanceof returns false (without resolving the class)2581TR::Node *iconst0 = TR::Node::iconst(0);2582TR::Node *store0 = TR::Node::createWithSymRef(TR::istore, 1, 1, iconst0, resultTemp);2583iconst0->copyByteCodeInfo(instanceofNode);2584store0->copyByteCodeInfo(instanceofNode);2585nullCaseBlock->append(TR::TreeTop::create(comp(), store0));2586TR::Node *gotoTail = TR::Node::create(TR::Goto, 0, tailBlock->getEntry());2587gotoTail->copyByteCodeInfo(instanceofNode);2588nullCaseBlock->append(TR::TreeTop::create(comp(), gotoTail));2589cfg()->addEdge(nullCaseBlock, tailBlock);25902591// In the non-null case, compute instanceof after resolving the class2592TR::TreeTop *newInstanceofTree = tree->duplicateTree();2593TR::Node *resultStoreNode = newInstanceofTree->getNode();2594resultStoreNode = TR::Node::recreateWithSymRef(resultStoreNode, TR::istore, resultTemp);2595TR::Node *classNode = resultStoreNode->getFirstChild()->getSecondChild();2596TR::Node *resolveCheckNode = genResolveCheck(classNode);2597resolveCheckNode->copyByteCodeInfo(instanceofNode);2598nonNullCaseBlock->append(TR::TreeTop::create(comp(), resolveCheckNode));2599nonNullCaseBlock->append(newInstanceofTree);26002601// Uses of the original instanceof will now load the temp instead2602instanceofNode = TR::Node::recreateWithSymRef(instanceofNode, TR::iload, resultTemp);2603instanceofNode->removeAllChildren();26042605// Remove the tree that was originally anchoring instanceof2606const bool decRefOriginalTreetopNode = true;2607tree->unlink(decRefOriginalTreetopNode);26082609if (trace)2610{2611traceMsg(comp(), "\tresult in temp #%d\n", resultTemp->getReferenceNumber());2612traceMsg(comp(), "\tblock_%d: resolve, instanceof\n", nonNullCaseBlock->getNumber());2613traceMsg(comp(), "\tblock_%d: false\n", nullCaseBlock->getNumber());2614traceMsg(comp(), "\tblock_%d: tail of original block\n", tailBlock->getNumber());2615}2616}26172618bool TR_J9ByteCodeIlGenerator::skipInvokeSpecialInterfaceTypeChecks()2619{2620static const bool disable =2621feGetEnv("TR_skipInvokeSpecialInterfaceTypeChecks") != NULL;2622return disable;2623}26242625/**2626* Expand a call tree for invokespecial within an interface.2627*2628* An explicit type test is inserted ahead of the call to ensure that the2629* receiver is an instance of the containing interface. The type test is in2630* terms of instanceof, so it will fail when the receiver is null. The call's2631* null check (if any) is moved before the type test so that it gets the first2632* opportunity to throw.2633*2634* Pictorially, transform this:2635*2636@verbatim2637+-<block_$orig>-------------+2638| ... $pre |2639| ... NULLCHK |2640| n1n call X.foo(...)T |2641| n2n $receiver |2642| ...args |2643| ... $post |2644+---------------------------+2645@endverbatim2646*2647* into the following, where @c $Interface is the interface type that was2648* detected for @c _invokeSpecialInterface:2649*2650@verbatim2651+-<block_$orig>------------------+2652| ... $pre |2653| ... NULLCHK |2654| ... PassThrough |2655| n2n $receiver |2656| ... astore $tmp_receiver |2657| n2n ==>$receiver |2658| ... (more fixupCommoning) |2659| ... ificmpne --> block_$ok |-----+2660| instanceof | |2661| ==>$receiver | |2662| loadaddr $Interface | |2663| iconst 0 | |2664+--------------------------------+ |2665| |2666fallthrough | |2667| |2668v |2669+-<block_$fail>-(cold)-------------+ |2670| ... (throw IllegalAccessError) | |2671+----------------------------------+ |2672|2673+-----------------------+2674|2675v2676+-<block_$ok>--------------------+2677| ... treetop |2678| n1n call X.foo(...)T |2679| ... aload $tmp_receiver |2680| ...args |2681| ... $post (w/ fixupCommoning) |2682+--------------------------------+2683@endverbatim2684*2685* @param tree The call tree as generated by the walker2686*/26872688void TR_J9ByteCodeIlGenerator::expandInvokeSpecialInterface(TR::TreeTop *tree)2689{2690TR_ASSERT(2691!comp()->compileRelocatableCode(),2692"in expandInvokeSpecialInterface under AOT\n");26932694TR_ASSERT(2695!skipInvokeSpecialInterfaceTypeChecks(),2696"in expandInvokeSpecialInterface, but it is disabled\n");26972698const bool trace = comp()->getOption(TR_TraceILGen);2699static const bool verbose =2700feGetEnv("TR_verboseInvokeSpecialInterface") != NULL;27012702if (trace)2703{2704traceMsg(comp(),2705"expanding invokespecial in interface method at n%un\n",2706tree->getNode()->getGlobalIndex());2707if (verbose)2708comp()->dumpMethodTrees("Trees before expanding invokespecial", _methodSymbol);2709}27102711TR::Node * const parent = tree->getNode();2712TR::Node * const callNode = parent->getChild(0);2713TR::Node * const receiver = callNode->getArgument(0);27142715// Temporarily set _bcIndex so that new nodes will pick it up2716const int32_t rememberedBcIndex = _bcIndex;2717_bcIndex = callNode->getByteCodeIndex();27182719// Separate the null check if there is one, so it will precede the type test.2720TR::TransformUtil::separateNullCheck(comp(), tree, trace);27212722// Insert the type test2723TR::SymbolReference * const ifaceSR =2724symRefTab()->findOrCreateClassSymbol(_methodSymbol, -1, _invokeSpecialInterface);2725TR::Node * const iface = TR::Node::createWithSymRef(TR::loadaddr, 0, ifaceSR);27262727TR::SymbolReference * const instofSR =2728symRefTab()->findOrCreateInstanceOfSymbolRef(_methodSymbol);2729TR::Node * const instof =2730TR::Node::createWithSymRef(TR::instanceof, 2, 2, receiver, iface, instofSR);27312732TR::Node * const typeTest = TR::Node::createif(2733TR::ificmpne,2734instof,2735TR::Node::iconst(0));27362737tree->insertBefore(TR::TreeTop::create(comp(), typeTest));27382739if (trace)2740traceMsg(comp(), "Inserted type test n%un\n", typeTest->getGlobalIndex());27412742// Split block between type test and call2743TR::Block * const headBlock = tree->getEnclosingBlock();27442745const bool fixupCommoning = true;2746TR::Block * const failBlock = headBlock->split(tree, cfg(), fixupCommoning);2747TR::Block * const okBlock = failBlock->split(tree, cfg(), fixupCommoning);27482749if (trace)2750{2751traceMsg(comp(),2752"Split block_%d into:\n"2753"\tblock_%d (preceding code, and type test),\n"2754"\tblock_%d (helper call for type test failure)\n"2755"\tblock_%d (successful call, and succeeding code)\n",2756headBlock->getNumber(),2757headBlock->getNumber(),2758failBlock->getNumber(),2759okBlock->getNumber());2760}27612762// Fix branch destination2763typeTest->setBranchDestination(okBlock->getEntry());2764cfg()->addEdge(headBlock, okBlock);27652766// Failure case: throw IllegalAccessError by calling jitThrowIncompatibleReceiver2767failBlock->setIsCold();2768failBlock->setFrequency(UNKNOWN_COLD_BLOCK_COUNT);27692770TR::Node * const rejectedVFT = TR::Node::createWithSymRef(2771TR::aloadi,27721,27731,2774callNode->getArgument(0)->duplicateTree(), // load split temp2775symRefTab()->findOrCreateVftSymbolRef());27762777TR::Node * const helperCall = TR::Node::createWithSymRef(2778TR::call,27792,27802,2781iface->duplicateTree(), // avoid commoning across blocks2782rejectedVFT,2783symRefTab()->findOrCreateIncompatibleReceiverSymbolRef(_methodSymbol));27842785failBlock->append(TR::TreeTop::create(comp(),2786TR::Node::create(TR::treetop, 1, helperCall)));27872788bool voidReturn = _methodSymbol->getResolvedMethod()->returnOpCode() == TR::Return;2789TR::Node *retNode = TR::Node::create(_methodSymbol->getResolvedMethod()->returnOpCode(), voidReturn?0:1);2790if (!voidReturn)2791{2792TR::Node *retValNode = TR::Node::create(comp()->il.opCodeForConst(_methodSymbol->getResolvedMethod()->returnType()), 0);2793retValNode->setLongInt(0);2794retNode->setAndIncChild(0, retValNode);2795}2796failBlock->append(TR::TreeTop::create(comp(), retNode));27972798if (trace)2799{2800traceMsg(comp(),2801"generated helper call n%un for type test failure\n",2802helperCall->getGlobalIndex());2803}28042805cfg()->removeEdge(failBlock, okBlock);2806cfg()->addEdge(failBlock, cfg()->getEnd());28072808if (trace && verbose)2809comp()->dumpMethodTrees("Trees after expanding invokespecial", _methodSymbol);28102811_bcIndex = rememberedBcIndex;2812}28132814TR::Node*2815TR_J9ByteCodeIlGenerator::loadFromMethodTypeTable(TR::Node* methodHandleInvokeCall)2816{2817int32_t cpIndex = next2Bytes();2818TR::SymbolReference *symRef = symRefTab()->findOrCreateMethodTypeTableEntrySymbol(_methodSymbol, cpIndex);2819TR::Node *methodType = TR::Node::createWithSymRef(methodHandleInvokeCall, TR::aload, 0, symRef);2820if (!symRef->isUnresolved())2821{2822if (_methodSymbol->getResolvedMethod()->methodTypeTableEntryAddress(cpIndex))2823methodType->setIsNonNull(true);2824else2825methodType->setIsNull(true);2826}28272828return methodType;2829}283028312832TR::Node*2833TR_J9ByteCodeIlGenerator::loadCallSiteMethodTypeFromCP(TR::Node* methodHandleInvokeCall)2834{2835int32_t cpIndex = next2Bytes();2836TR_ASSERT(method()->isMethodTypeConstant(cpIndex), "Address-type CP entry %d must be methodType", cpIndex);2837TR::SymbolReference *symRef = symRefTab()->findOrCreateMethodTypeSymbol(_methodSymbol, cpIndex);2838TR::Node* methodType = TR::Node::createWithSymRef(methodHandleInvokeCall, TR::aload, 0, symRef);2839return methodType;2840}28412842TR::Node*2843TR_J9ByteCodeIlGenerator::loadCallSiteMethodType(TR::Node* methodHandleInvokeCall)2844{2845if (fej9()->hasMethodTypesSideTable())2846return loadFromMethodTypeTable(methodHandleInvokeCall);2847else2848return loadCallSiteMethodTypeFromCP(methodHandleInvokeCall);2849}28502851void TR_J9ByteCodeIlGenerator::insertCustomizationLogicTreeIfEnabled(TR::TreeTop* tree, TR::Node* methodHandle)2852{2853if (comp()->getOption(TR_EnableMHCustomizationLogicCalls))2854{2855TR::SymbolReference *doCustomizationLogic = comp()->getSymRefTab()->methodSymRefFromName(_methodSymbol, JSR292_MethodHandle, "doCustomizationLogic", "()V", TR::MethodSymbol::Special);2856TR::Node* customization = TR::Node::createWithSymRef(TR::call, 1, 1, methodHandle, doCustomizationLogic);2857customization->getByteCodeInfo().setDoNotProfile(true);2858tree->insertBefore(TR::TreeTop::create(comp(), TR::Node::create(TR::treetop, 1, customization)));28592860if (comp()->getOption(TR_TraceILGen))2861{2862traceMsg(comp(), "Inserted call to doCustomizationLogic n%dn %p\n", customization->getGlobalIndex(), customization);2863}2864}2865}28662867/** \brief2868* Expand a MethodHandle.invokeExact call generated from invokeHandle2869*2870* Transforms the following tree2871*2872@verbatim2873... NULLCHK2874n1n xcalli MethodHandle.invokeExact2875n2n lconst 02876n3n $receiver2877...args2878@endverbatim2879*2880* into2881*2882@verbatim2883... NULLCHK2884... PassThrough2885n3n $receiver2886... acall MethodHandle.getType2887==>$receiver2888... ZEROCHK2889acmpeq2890$callSiteMethodType2891==>acall MethodHandle.getType2892... lcall MethodHandle.invokeExactTargetAddress2893==>$receiver2894n1n xcalli MethodHandle.invokeExact2895==>lcall MethodHandle.invokeExactTargetAddress2896==>$receiver2897...args2898@endverbatim2899*2900* \param tree2901* Tree of the invokeHandle call.2902*2903* \note2904* A call to doCustomizationLogic will be inserted if customization2905* logic is enabled for invocations outside of thunk archetype.2906*/2907void TR_J9ByteCodeIlGenerator::expandInvokeHandle(TR::TreeTop *tree)2908{2909TR_ASSERT(!comp()->compileRelocatableCode(), "in expandInvokeHandle under AOT\n");29102911if (comp()->getOption(TR_TraceILGen))2912{2913traceMsg(comp(), "expanding invokehandle at n%dn\n", tree->getNode()->getGlobalIndex());2914}29152916TR::Node * callNode = tree->getNode()->getChild(0);2917TR::Node * receiverHandle = callNode->getArgument(0);2918callNode->getByteCodeInfo().setDoNotProfile(true);29192920TR::Node* callSiteMethodType = loadCallSiteMethodType(callNode);29212922if (callSiteMethodType->getSymbolReference()->isUnresolved())2923{2924TR::Node *resolveChkOnMethodType = TR::Node::createWithSymRef(callNode, TR::ResolveCHK, 1, callSiteMethodType, comp()->getSymRefTab()->findOrCreateResolveCheckSymbolRef(_methodSymbol));2925tree->insertBefore(TR::TreeTop::create(comp(), resolveChkOnMethodType));2926}29272928// Generate zerochk2929TR::Node* zerochkNode = genHandleTypeCheck(receiverHandle, callSiteMethodType);2930tree->insertBefore(TR::TreeTop::create(comp(), zerochkNode));29312932if (comp()->getOption(TR_TraceILGen))2933{2934traceMsg(comp(), "Inserted ZEROCHK n%dn %p\n", zerochkNode->getGlobalIndex(), zerochkNode);2935}29362937insertCustomizationLogicTreeIfEnabled(tree, receiverHandle);29382939expandInvokeExact(tree);2940}29412942/** \brief2943* Expand a MethodHandle.invokeExact call generated from invokeDynamic.2944*2945* Transforms the following tree2946*2947@verbatim2948... NULLCHK2949n1n xcalli MethodHandle.invokeExact2950n2n lconst 02951n3n $receiver2952...args2953@endverbatim2954*2955* into2956*2957@verbatim2958... NULLCHK2959... PassThrough2960n3n $receiver2961... lcall MethodHandle.invokeExactTargetAddress2962==>$receiver2963n1n xcalli MethodHandle.invokeExact2964==>lcall MethodHandle.invokeExactTargetAddress2965==>$receiver2966...args2967@endverbatim2968*2969* \param tree2970* Tree of the invokeExact call.2971*2972* \note2973* A call to doCustomizationLogic will be inserted if customization2974* logic is enabled for invocations outside of thunk archetype.2975*/2976void TR_J9ByteCodeIlGenerator::expandInvokeDynamic(TR::TreeTop *tree)2977{2978TR_ASSERT(!comp()->compileRelocatableCode(), "in expandInvokeDynamic under AOT\n");29792980if (comp()->getOption(TR_TraceILGen))2981{2982traceMsg(comp(), "expanding invokeDynamic at n%dn\n", tree->getNode()->getGlobalIndex());2983}29842985TR::Node * callNode = tree->getNode()->getChild(0);2986TR::Node * receiverHandle = callNode->getArgument(0);2987callNode->getByteCodeInfo().setDoNotProfile(true);29882989insertCustomizationLogicTreeIfEnabled(tree, receiverHandle);2990expandInvokeExact(tree);2991}29922993/** \brief2994* Expand a MethodHandle.invokeExact call generated from invokeHandleGeneric.2995*2996* Transforms the following tree2997*2998@verbatim2999... NULLCHK3000n1n xcalli MethodHandle.invokeExact3001n2n lconst 03002n3n $receiver3003...args3004@endverbatim3005*3006* into3007*3008@verbatim3009... NULLCHK3010... PassThrough3011n3n $receiver3012... acall MethodHandle.asType3013==>$receiver3014... $callSiteMethodType3015... lcall MethodHandle.invokeExactTargetAddress3016==>acall MethodHandle.asType3017n1n xcalli MethodHandle.invokeExact3018==>lcall MethodHandle.invokeExactTargetAddress3019==>acall MethodHandle.asType3020...args3021@endverbatim3022*3023* \param tree3024* Tree of the invokeExact call.3025*3026* \note3027* A call to doCustomizationLogic will be inserted if customization3028* logic is enabled for invocations outside of thunk archetype.3029*3030*/3031void TR_J9ByteCodeIlGenerator::expandInvokeHandleGeneric(TR::TreeTop *tree)3032{3033TR_ASSERT(!comp()->compileRelocatableCode(), "in expandInvokeHandleGeneric under AOT\n");30343035if (comp()->getOption(TR_TraceILGen))3036{3037traceMsg(comp(), "expanding invokeHandleGeneric at n%dn\n", tree->getNode()->getGlobalIndex());3038}30393040TR::Node * callNode = tree->getNode()->getChild(0);3041TR::Node * receiverHandle = callNode->getArgument(0);3042callNode->getByteCodeInfo().setDoNotProfile(true);30433044TR::Node* callSiteMethodType = loadCallSiteMethodType(callNode);3045if (callSiteMethodType->getSymbolReference()->isUnresolved())3046{3047TR::Node *resolveChkOnMethodType = TR::Node::createWithSymRef(callNode, TR::ResolveCHK, 1, callSiteMethodType, comp()->getSymRefTab()->findOrCreateResolveCheckSymbolRef(_methodSymbol));3048tree->insertBefore(TR::TreeTop::create(comp(), resolveChkOnMethodType));3049}30503051TR::SymbolReference *typeConversionSymRef = comp()->getSymRefTab()->methodSymRefFromName(_methodSymbol, JSR292_MethodHandle, JSR292_asType, JSR292_asTypeSig, TR::MethodSymbol::Static);3052TR::Node* asType = TR::Node::createWithSymRef(callNode, TR::acall, 2, typeConversionSymRef);3053asType->setAndIncChild(0, receiverHandle);3054asType->setAndIncChild(1, callSiteMethodType);3055asType->getByteCodeInfo().setDoNotProfile(true);3056tree->insertBefore(TR::TreeTop::create(comp(), TR::Node::create(callNode, TR::treetop, 1, asType)));30573058if (comp()->getOption(TR_TraceILGen))3059{3060traceMsg(comp(), "Inserted asType call n%dn %p\n", asType->getGlobalIndex(), asType);3061}30623063int32_t receiverChildIndex = callNode->getFirstArgumentIndex();3064callNode->setAndIncChild(receiverChildIndex, asType);3065receiverHandle->recursivelyDecReferenceCount();30663067insertCustomizationLogicTreeIfEnabled(tree, asType);30683069expandInvokeExact(tree);3070}30713072/** \brief3073* Expand a MethodHandle.invokeExact call.3074*3075* Transforms the following tree3076*3077@verbatim3078... NULLCHK3079n1n xcalli MethodHandle.invokeExact3080n2n lconst 03081n3n $receiver3082...args3083@endverbatim3084*3085* into3086*3087@verbatim3088... NULLCHK3089... PassThrough3090n3n $receiver3091... lcall MethodHandle.invokeExactTargetAddress3092==>$receiver3093n1n xcalli MethodHandle.invokeExact3094==>lcall MethodHandle.invokeExactTargetAddress3095==>$receiver3096...args3097@endverbatim3098*3099* \param tree3100* Tree of the invokeExact call.3101*/3102void TR_J9ByteCodeIlGenerator::expandInvokeExact(TR::TreeTop *tree)3103{3104TR_ASSERT(!comp()->compileRelocatableCode(), "in expandInvokeExact under AOT\n");31053106if (comp()->getOption(TR_TraceILGen))3107{3108traceMsg(comp(), "expanding invokeExact at n%dn\n", tree->getNode()->getGlobalIndex());3109}31103111TR::Node * callNode = tree->getNode()->getChild(0);3112TR::Node * receiverHandle = callNode->getArgument(0);3113callNode->getByteCodeInfo().setDoNotProfile(true);31143115// Get the method address3116uint32_t offset = fej9()->getInstanceFieldOffsetIncludingHeader("Ljava/lang/invoke/MethodHandle;", "thunks", "Ljava/lang/invoke/ThunkTuple;", method());3117TR::SymbolReference *thunksSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(_methodSymbol,3118TR::Symbol::Java_lang_invoke_MethodHandle_thunks,3119TR::Address,3120offset,3121false,3122false,3123false,3124"java/lang/invoke/MethodHandle.thunks Ljava/lang/invoke/ThunkTuple;");3125TR::Node *thunksNode = TR::Node::createWithSymRef(callNode, comp()->il.opCodeForIndirectLoad(TR::Address), 1, receiverHandle, thunksSymRef);3126thunksNode->setIsNonNull(true);312731283129offset = fej9()->getInstanceFieldOffsetIncludingHeader("Ljava/lang/invoke/ThunkTuple;", "invokeExactThunk", "J", method());3130TR::SymbolReference *invokeExactTargetAddrSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(_methodSymbol,3131TR::Symbol::Java_lang_invoke_ThunkTuple_invokeExactThunk,3132TR::Int64,3133offset,3134false,3135false,3136true,3137"java/lang/invoke/ThunkTuple.invokeExactThunk J");3138TR::Node *invokeExactTargetAddr = TR::Node::createWithSymRef(callNode, comp()->il.opCodeForIndirectLoad(TR::Int64), 1, thunksNode, invokeExactTargetAddrSymRef);3139tree->insertBefore(TR::TreeTop::create(comp(), TR::Node::create(callNode, TR::treetop, 1, invokeExactTargetAddr)));31403141if (comp()->getOption(TR_TraceILGen))3142{3143traceMsg(comp(), "Replacing first child n%dn with invoke exact thunk address n%dn\n", callNode->getFirstChild()->getGlobalIndex(), invokeExactTargetAddr->getGlobalIndex());3144}31453146// Replace the `lconst 0` node with the actual thunk address3147TR::Node *lnode = callNode->getFirstChild();3148callNode->setAndIncChild(0, invokeExactTargetAddr);3149lnode->decReferenceCount();3150}31513152/** \brief3153* Expand MethodHandle.invokeExact calls generated from different bytecodes.3154*3155* \param tree3156* Tree of the invokeExact call.3157*/3158void TR_J9ByteCodeIlGenerator::expandMethodHandleInvokeCall(TR::TreeTop *tree)3159{3160TR::Node *ttNode = tree->getNode();3161TR::Node* callNode = ttNode->getFirstChild();3162TR::TreeTop* prevTree = tree->getPrevTreeTop();3163TR::TreeTop* nextTree = tree->getNextTreeTop();31643165if (comp()->getOption(TR_TraceILGen))3166{3167traceMsg(comp(), "Found MethodHandle invoke call n%dn %p to expand\n", callNode->getGlobalIndex(), callNode);3168traceMsg(comp(), " /--- Tree before expanding n%dn --------------------\n", callNode->getGlobalIndex());3169comp()->getDebug()->printWithFixedPrefix(comp()->getOutFile(), ttNode, 1, true, true, " ");3170traceMsg(comp(), "\n");3171}31723173int32_t oldBCIndex = _bcIndex;3174_bcIndex = callNode->getByteCodeIndex();31753176// Preserve the NULLCHK3177//3178TR::TransformUtil::separateNullCheck(comp(), tree, comp()->getOption(TR_TraceILGen));3179// Anchor all children3180//3181for (int i = callNode->getFirstArgumentIndex(); i < callNode->getNumChildren(); i++)3182{3183TR::Node* child = callNode->getChild(i);3184TR::TreeTop *anchorTT = TR::TreeTop::create(comp(), TR::Node::create(TR::treetop, 1, child));3185if (comp()->getOption(TR_TraceILGen))3186{3187traceMsg(comp(), "TreeTop n%dn is created to anchor node n%dn\n", anchorTT->getNode()->getGlobalIndex(), child->getGlobalIndex());3188}3189tree->insertBefore(anchorTT);3190}31913192if (_invokeHandleCalls &&3193_invokeHandleCalls->isSet(_bcIndex))3194{3195expandInvokeHandle(tree);3196}3197else if (_invokeHandleGenericCalls &&3198_invokeHandleGenericCalls->isSet(_bcIndex))3199{3200expandInvokeHandleGeneric(tree);3201}3202else if (_invokeDynamicCalls &&3203_invokeDynamicCalls->isSet(_bcIndex))3204{3205expandInvokeDynamic(tree);3206}3207else if (_ilGenMacroInvokeExactCalls &&3208_ilGenMacroInvokeExactCalls->isSet(_bcIndex))3209{3210expandInvokeExact(tree);3211}3212else3213{3214TR_ASSERT(comp(), "Unexpected MethodHandle invoke call at n%dn %p", callNode->getGlobalIndex(), callNode);3215}32163217// Specialize MethodHandle.invokeExact if the receiver handle is a known object3218TR::Node* methodHandle = callNode->getFirstArgument();3219if (methodHandle->getOpCode().hasSymbolReference()3220&& methodHandle->getSymbolReference()->hasKnownObjectIndex())3221{3222TR::KnownObjectTable::Index index = methodHandle->getSymbolReference()->getKnownObjectIndex();3223uintptr_t* objectLocation = comp()->getKnownObjectTable()->getPointerLocation(index);3224TR::TransformUtil::specializeInvokeExactSymbol(comp(), callNode, objectLocation);3225}32263227_bcIndex = oldBCIndex;32283229if (comp()->getOption(TR_TraceILGen))3230{3231traceMsg(comp(), " /--- Trees after expanding n%dn --------------------\n", callNode->getGlobalIndex());3232TR::TreeTop *tt = prevTree->getNextTreeTop();3233do3234{3235comp()->getDebug()->printWithFixedPrefix(comp()->getOutFile(), tt->getNode(), 1, true, true, " ");3236traceMsg(comp(), "\n");3237tt = tt->getNextTreeTop();3238} while( tt != nextTree);3239}3240}324132423243