Path: blob/master/runtime/compiler/ilgen/Walker.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2000, 2022 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 <algorithm>23#include "codegen/CodeGenerator.hpp"24#include "compile/InlineBlock.hpp"25#include "compile/Method.hpp"26#include "compile/ResolvedMethod.hpp"27#include "control/Recompilation.hpp"28#include "control/RecompilationInfo.hpp"29#include "env/CompilerEnv.hpp"30#include "env/PersistentCHTable.hpp"31#include "env/StackMemoryRegion.hpp"32#include "env/TypeLayout.hpp"33#include "env/jittypes.h"34#include "env/VMAccessCriticalSection.hpp"35#include "env/VerboseLog.hpp"36#include "exceptions/AOTFailure.hpp"37#include "exceptions/FSDFailure.hpp"38#include "exceptions/RuntimeFailure.hpp"39#include "optimizer/TransformUtil.hpp"40#include "il/Node.hpp"41#include "il/Node_inlines.hpp"42#include "il/TreeTop.hpp"43#include "il/TreeTop_inlines.hpp"44#include "env/j9fieldsInfo.h"45#include "env/VMJ9.h"46#include "ilgen/ClassLookahead.hpp"47#include "ilgen/J9ByteCode.hpp"48#include "ilgen/J9ByteCodeIlGenerator.hpp"49#include "infra/Bit.hpp" //for trailingZeroes50#include "env/JSR292Methods.h"5152#if defined(J9VM_OPT_JITSERVER)53#include "env/j9methodServer.hpp"54#endif5556#define JAVA_SERIAL_CLASS_NAME "Ljava/io/ObjectInputStream;"57#define JAVA_SERIAL_CLASS_NAME_LEN 2758#define JAVA_SERIAL_CALLEE_METHOD_NAME_LEN 1059#define JAVA_SERIAL_CALLEE_METHOD_NAME "readObject"60#define JAVA_SERIAL_CALLEE_METHOD_SIG_LEN 2061#define JAVA_SERIAL_CALLEE_METHOD_SIG "()Ljava/lang/Object;"62#define JAVA_SERIAL_REPLACE_CLASS_LEN 2563#define JAVA_SERIAL_REPLACE_CLASS_NAME "java/io/ObjectInputStream"64#define JAVA_SERIAL_REPLACE_METHOD_SIG_LEN 6465#define JAVA_SERIAL_REPLACE_METHOD_SIG "(Ljava/io/ObjectInputStream;Ljava/lang/Class;)Ljava/lang/Object;"66#define JAVA_SERIAL_REPLACE_METHOD_NAME_LEN 2067#define JAVA_SERIAL_REPLACE_METHOD_NAME "redirectedReadObject"6869#define ORB_CALLER_METHOD_NAME_LEN 1070#define ORB_CALLER_METHOD_NAME "readObject"71#define ORB_CALLER_METHOD_SIG_LEN 3072#define ORB_CALLER_METHOD_SIG "(Ljava/io/ObjectInputStream;)V"7374#define ORB_CALLEE_METHOD_NAME_LEN 1075#define ORB_CALLEE_METHOD_NAME "readObject"76#define ORB_CALLEE_METHOD_SIG_LEN 2077#define ORB_CALLEE_METHOD_SIG "()Ljava/lang/Object;"7879#define ORB_REPLACE_CLASS_LEN 3080#define ORB_REPLACE_CLASS_NAME "com/ibm/rmi/io/IIOPInputStream"81#define ORB_REPLACE_METHOD_SIG_LEN 6482#define ORB_REPLACE_METHOD_SIG "(Ljava/io/ObjectInputStream;Ljava/lang/Class;)Ljava/lang/Object;"83#define ORB_REPLACE_METHOD_NAME_LEN 2084#define ORB_REPLACE_METHOD_NAME "redirectedReadObject"8586#define JSR292_ILGenMacros "java/lang/invoke/ILGenMacros"87#define JSR292_placeholder "placeholder"88#define JSR292_placeholderSig "(I)I"8990#define JSR292_MethodHandle "java/lang/invoke/MethodHandle"91#define JSR292_invokeExactTargetAddress "invokeExactTargetAddress"92#define JSR292_invokeExactTargetAddressSig "()J"93#define JSR292_getType "type"94#define JSR292_getTypeSig "()Ljava/lang/invoke/MethodType;"9596#define JSR292_invokeExact "invokeExact"97#define JSR292_invokeExactSig "([Ljava/lang/Object;)Ljava/lang/Object;"9899#define JSR292_ComputedCalls "java/lang/invoke/ComputedCalls"100#define JSR292_dispatchDirectPrefix "dispatchDirect_"101#define JSR292_dispatchDirectArgSig "(JI)"102103#define JSR292_asType "asType"104#define JSR292_asTypeSig "(Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;"105#define JSR292_forGenericInvoke "forGenericInvoke"106#define JSR292_forGenericInvokeSig "(Ljava/lang/invoke/MethodType;Z)Ljava/lang/invoke/MethodHandle;"107108109static void printStack(TR::Compilation *comp, TR_Stack<TR::Node*> *stack, const char *message)110{111// TODO: This should be in the debug DLL112if (stack->isEmpty())113{114traceMsg(comp, " ---- %s: empty -----------------\n", message);115}116else117{118TR_BitVector nodesAlreadyPrinted(comp->getNodeCount(), comp->trMemory(), stackAlloc, growable);119comp->getDebug()->saveNodeChecklist(nodesAlreadyPrinted);120char buf[30];121traceMsg(comp, " /--- %s ------------------------", message);122for (int i = stack->topIndex(); i >= 0; --i)123{124TR::Node *node = stack->element(i);125traceMsg(comp, "\n");126sprintf(buf, " @%-2d", i);127comp->getDebug()->printWithFixedPrefix(comp->getOutFile(), node, 1, false, true, buf);128if (!nodesAlreadyPrinted.isSet(node->getGlobalIndex()))129{130for (int j = 0; j < node->getNumChildren(); ++j)131{132traceMsg(comp, "\n");133comp->getDebug()->printWithFixedPrefix(comp->getOutFile(), node->getChild(j), 3, true, true, " ");134}135}136}137traceMsg(comp, "\n");138}139}140141static void printTrees(TR::Compilation *comp, TR::TreeTop *firstTree, TR::TreeTop *stopTree, const char *message)142{143// TODO: This should be in the debug DLL144if (firstTree == stopTree)145{146traceMsg(comp, " ---- %s: none ------------------\n", message);147}148else149{150traceMsg(comp, " /--- %s ------------------------", message);151for (TR::TreeTop *tt = firstTree; tt && tt != stopTree; tt = tt->getNextTreeTop())152{153traceMsg(comp, "\n");154comp->getDebug()->printWithFixedPrefix(comp->getOutFile(), tt->getNode(), 1, true, true, " ");155}156traceMsg(comp, "\n");157}158}159160static TR::ILOpCodes getCallOpForType(TR::DataType type)161{162switch(type)163{164case TR::Address: return TR::acall;165case TR::Float : return TR::fcall;166case TR::Double: return TR::dcall;167case TR::Int32:168case TR::Int16:169case TR::Int8: return TR::icall;170case TR::Int64:return TR::lcall;171default: TR_ASSERT(false, "assertion failure");172}173return TR::BadILOp;174}175176#define DCAS_AVAILABLE_FLAG "dWordCASSupported"177#define DCAS_AVAILABLE_FLAG_LEN 17178#define DCAS_AVAILABLE_FLAG_SIG "Z"179#define DCAS_AVAILABLE_FLAG_SIG_LEN 1180181#define DSET_AVAILABLE_FLAG "dWordSetSupported"182#define DSET_AVAILABLE_FLAG_LEN 17183#define DSET_AVAILABLE_FLAG_SIG "Z"184#define DSET_AVAILABLE_FLAG_SIG_LEN 1185186TR::Block * TR_J9ByteCodeIlGenerator::walker(TR::Block * prevBlock)187{188int32_t i, lastIndex = _bcIndex, firstIndex = _bcIndex;189190if (comp()->getOption(TR_TraceILGen))191{192comp()->getDebug()->clearNodeChecklist();193traceMsg(comp(), "==== Starting ILGen walker at bytecode %x", _bcIndex);194if (_argPlaceholderSlot != -1)195traceMsg(comp(), " argPlaceholderSlot=%d", _argPlaceholderSlot);196traceMsg(comp(), "\n");197}198199200#if defined(J9VM_OPT_JITSERVER)201if (prevBlock == 0 && comp()->isOutOfProcessCompilation() && _methodSymbol->getResolvedMethod())202{203// Every J9BCinvoke* bytecode requires a corresponding resolved method for its method symbol.204// Prefetch resolved methods in one message.205// For unresolved methods, allow the next 2 requests to return NULL without asking the client,206// since they happen almost immediately after this one and method is unlikely to become resolved.207//208// NOTE: first request occurs in the switch statement over bytecodes,209// second request occurs in stashArgumentsForOSR210if (_methodSymbol->getResolvedMethod() == comp()->getMethodBeingCompiled())211static_cast<TR_ResolvedJ9JITServerMethod *>(_methodSymbol->getResolvedMethod())->cacheResolvedMethodsCallees(2);212213214// Cache field info for every field/static loaded/stored in this method, which are later used by215// jitFieldsAreSame/jitStaticAreSame when creating symbol references.216static_cast<TR_ResolvedJ9JITServerMethod *>(_methodSymbol->getResolvedMethod())->cacheFields();217}218#endif219220while (_bcIndex < _maxByteCodeIndex)221{222if (blocks(_bcIndex) && blocks(_bcIndex) != _block)223{224if (isGenerated(_bcIndex))225_bcIndex = genGoto(_bcIndex);226else227_bcIndex = genBBEndAndBBStart();228if (_bcIndex >= _maxByteCodeIndex)229break;230}231232if (_bcIndex < firstIndex)233firstIndex = _bcIndex;234else if (_bcIndex > lastIndex)235lastIndex = _bcIndex;236237TR_ASSERT(!isGenerated(_bcIndex), "Walker error");238setIsGenerated(_bcIndex);239240uint8_t opcode = _code[_bcIndex];241242TR::TreeTop *traceStop = _block->getExit();243TR::TreeTop *traceStart = traceStop->getPrevTreeTop();244if (comp()->getOption(TR_TraceILGen))245traceMsg(comp(), "%4x: %s\n", _bcIndex, ((TR_J9VM *)fej9())->getByteCodeName(opcode));246247_bc = convertOpCodeToByteCodeEnum(opcode);248stashArgumentsForOSR(_bc);249switch (_bc)250{251case J9BCinvokeinterface2:252case J9BCnop: _bcIndex += 1; break;253254case J9BCaconstnull: loadConstant(TR::aconst, (void *)0); _bcIndex += 1; break;255case J9BCiconstm1: loadConstant(TR::iconst, -1); _bcIndex += 1; break;256257case J9BCiconst0: loadConstant(TR::iconst, 0); _bcIndex += 1; break;258case J9BCiconst1: loadConstant(TR::iconst, 1); _bcIndex += 1; break;259case J9BCiconst2: loadConstant(TR::iconst, 2); _bcIndex += 1; break;260case J9BCiconst3: loadConstant(TR::iconst, 3); _bcIndex += 1; break;261case J9BCiconst4: loadConstant(TR::iconst, 4); _bcIndex += 1; break;262case J9BCiconst5: loadConstant(TR::iconst, 5); _bcIndex += 1; break;263264case J9BClconst0: loadConstant(TR::lconst, (int64_t)0); _bcIndex += 1; break;265case J9BClconst1: loadConstant(TR::lconst, (int64_t)1); _bcIndex += 1; break;266267case J9BCfconst0: loadConstant(TR::fconst, 0.0f); _bcIndex += 1; break;268case J9BCfconst1: loadConstant(TR::fconst, 1.0f); _bcIndex += 1; break;269case J9BCfconst2: loadConstant(TR::fconst, 2.0f); _bcIndex += 1; break;270271case J9BCdconst0: loadConstant(TR::dconst, 0.0); _bcIndex += 1; break;272case J9BCdconst1: loadConstant(TR::dconst, 1.0); _bcIndex += 1; break;273274case J9BCldc: loadFromCP(TR::NoType, nextByte()); _bcIndex += 2; break;275case J9BCldcw: loadFromCP(TR::NoType, next2Bytes()); _bcIndex += 3; break;276case J9BCldc2lw: loadFromCP(TR::NoType, next2Bytes()); _bcIndex += 3; break;277case J9BCldc2dw: loadFromCP(TR::NoType, next2Bytes()); _bcIndex += 3; break;278279case J9BCiload0: loadAuto(TR::Int32, 0); _bcIndex += 1; break;280case J9BCiload1: loadAuto(TR::Int32, 1); _bcIndex += 1; break;281case J9BCiload2: loadAuto(TR::Int32, 2); _bcIndex += 1; break;282case J9BCiload3: loadAuto(TR::Int32, 3); _bcIndex += 1; break;283284case J9BClload0: loadAuto(TR::Int64, 0); _bcIndex += 1; break;285case J9BClload1: loadAuto(TR::Int64, 1); _bcIndex += 1; break;286case J9BClload2: loadAuto(TR::Int64, 2); _bcIndex += 1; break;287case J9BClload3: loadAuto(TR::Int64, 3); _bcIndex += 1; break;288289case J9BCfload0: loadAuto(TR::Float, 0); _bcIndex += 1; break;290case J9BCfload1: loadAuto(TR::Float, 1); _bcIndex += 1; break;291case J9BCfload2: loadAuto(TR::Float, 2); _bcIndex += 1; break;292case J9BCfload3: loadAuto(TR::Float, 3); _bcIndex += 1; break;293294case J9BCdload0: loadAuto(TR::Double, 0); _bcIndex += 1; break;295case J9BCdload1: loadAuto(TR::Double, 1); _bcIndex += 1; break;296case J9BCdload2: loadAuto(TR::Double, 2); _bcIndex += 1; break;297case J9BCdload3: loadAuto(TR::Double, 3); _bcIndex += 1; break;298299case J9BCaload0: loadAuto(TR::Address, 0); _bcIndex += 1; break;300case J9BCaload1: loadAuto(TR::Address, 1); _bcIndex += 1; break;301case J9BCaload2: loadAuto(TR::Address, 2); _bcIndex += 1; break;302case J9BCaload3: loadAuto(TR::Address, 3); _bcIndex += 1; break;303304case J9BCiaload: loadArrayElement(TR::Int32); _bcIndex += 1; break;305case J9BClaload: loadArrayElement(TR::Int64); _bcIndex += 1; break;306case J9BCfaload: loadArrayElement(TR::Float); _bcIndex += 1; break;307case J9BCdaload: loadArrayElement(TR::Double); _bcIndex += 1; break;308case J9BCaaload: loadArrayElement(TR::Address); _bcIndex += 1; break;309case J9BCbaload: loadArrayElement(TR::Int8); genUnary(TR::b2i); _bcIndex += 1; break;310case J9BCcaload: loadArrayElement(TR::Int16); genUnary(TR::su2i); _bcIndex += 1; break;311case J9BCsaload: loadArrayElement(TR::Int16); genUnary(TR::s2i); _bcIndex += 1; break;312313case J9BCiloadw: loadAuto(TR::Int32, next2Bytes()); _bcIndex += 3; break;314case J9BClloadw: loadAuto(TR::Int64, next2Bytes()); _bcIndex += 3; break;315case J9BCfloadw: loadAuto(TR::Float, next2Bytes()); _bcIndex += 3; break;316case J9BCdloadw: loadAuto(TR::Double, next2Bytes()); _bcIndex += 3; break;317case J9BCaloadw: loadAuto(TR::Address, next2Bytes()); _bcIndex += 3; break;318319case J9BCbipush: loadConstant(TR::iconst, nextByteSigned()); _bcIndex += 2; break;320case J9BCsipush: loadConstant(TR::iconst, next2BytesSigned()); _bcIndex += 3; break;321322case J9BCiload: loadAuto(TR::Int32, nextByte()); _bcIndex += 2; break;323case J9BClload: loadAuto(TR::Int64, nextByte()); _bcIndex += 2; break;324case J9BCfload: loadAuto(TR::Float, nextByte()); _bcIndex += 2; break;325case J9BCdload: loadAuto(TR::Double, nextByte()); _bcIndex += 2; break;326case J9BCaload: loadAuto(TR::Address, nextByte()); _bcIndex += 2; break;327328case J9BCistore: storeAuto(TR::Int32, nextByte()); _bcIndex += 2; break;329case J9BClstore: storeAuto(TR::Int64, nextByte()); _bcIndex += 2; break;330case J9BCfstore: storeAuto(TR::Float, nextByte()); _bcIndex += 2; break;331case J9BCdstore: storeAuto(TR::Double, nextByte()); _bcIndex += 2; break;332case J9BCastore: storeAuto(TR::Address, nextByte()); _bcIndex += 2; break;333334case J9BCistore0: storeAuto(TR::Int32, 0); _bcIndex += 1; break;335case J9BCistore1: storeAuto(TR::Int32, 1); _bcIndex += 1; break;336case J9BCistore2: storeAuto(TR::Int32, 2); _bcIndex += 1; break;337case J9BCistore3: storeAuto(TR::Int32, 3); _bcIndex += 1; break;338339case J9BClstore0: storeAuto(TR::Int64, 0); _bcIndex += 1; break;340case J9BClstore1: storeAuto(TR::Int64, 1); _bcIndex += 1; break;341case J9BClstore2: storeAuto(TR::Int64, 2); _bcIndex += 1; break;342case J9BClstore3: storeAuto(TR::Int64, 3); _bcIndex += 1; break;343344case J9BCfstore0: storeAuto(TR::Float, 0); _bcIndex += 1; break;345case J9BCfstore1: storeAuto(TR::Float, 1); _bcIndex += 1; break;346case J9BCfstore2: storeAuto(TR::Float, 2); _bcIndex += 1; break;347case J9BCfstore3: storeAuto(TR::Float, 3); _bcIndex += 1; break;348349case J9BCdstore0: storeAuto(TR::Double, 0); _bcIndex += 1; break;350case J9BCdstore1: storeAuto(TR::Double, 1); _bcIndex += 1; break;351case J9BCdstore2: storeAuto(TR::Double, 2); _bcIndex += 1; break;352case J9BCdstore3: storeAuto(TR::Double, 3); _bcIndex += 1; break;353354case J9BCastore0: storeAuto(TR::Address, 0); _bcIndex += 1; break;355case J9BCastore1: storeAuto(TR::Address, 1); _bcIndex += 1; break;356case J9BCastore2: storeAuto(TR::Address, 2); _bcIndex += 1; break;357case J9BCastore3: storeAuto(TR::Address, 3); _bcIndex += 1; break;358359case J9BCiastore: storeArrayElement(TR::Int32); _bcIndex += 1; break;360case J9BClastore: storeArrayElement(TR::Int64); _bcIndex += 1; break;361case J9BCfastore: storeArrayElement(TR::Float); _bcIndex += 1; break;362case J9BCdastore: storeArrayElement(TR::Double); _bcIndex += 1; break;363case J9BCaastore: storeArrayElement(TR::Address); _bcIndex += 1; break;364case J9BCbastore: genUnary(TR::i2b); storeArrayElement(TR::Int8); _bcIndex += 1; break;365case J9BCcastore: genUnary(TR::i2s); storeArrayElement(TR::Int16);_bcIndex += 1; break;366case J9BCsastore: genUnary(TR::i2s); storeArrayElement(TR::Int16); _bcIndex += 1; break;367368case J9BCistorew: storeAuto(TR::Int32, next2Bytes()); _bcIndex += 3; break;369case J9BClstorew: storeAuto(TR::Int64, next2Bytes()); _bcIndex += 3; break;370case J9BCfstorew: storeAuto(TR::Float, next2Bytes()); _bcIndex += 3; break;371case J9BCdstorew: storeAuto(TR::Double, next2Bytes()); _bcIndex += 3; break;372case J9BCastorew: storeAuto(TR::Address, next2Bytes()); _bcIndex += 3; break;373374case J9BCpop: eat1(); _bcIndex += 1; break;375case J9BCpop2: eat2(); _bcIndex += 1; break;376case J9BCdup: dup(); _bcIndex += 1; break;377case J9BCdup2: dup2(); _bcIndex += 1; break;378case J9BCdupx1: dupx1(); _bcIndex += 1; break;379case J9BCdup2x1: dup2x1(); _bcIndex += 1; break;380case J9BCdupx2: dupx2(); _bcIndex += 1; break;381case J9BCdup2x2: dup2x2(); _bcIndex += 1; break;382case J9BCswap: swap(); _bcIndex += 1; break;383384case J9BCiadd: genBinary(TR::iadd); _bcIndex += 1; break;385case J9BCladd: genBinary(TR::ladd); _bcIndex += 1; break;386case J9BCfadd: genBinary(TR::fadd); _bcIndex += 1; break;387case J9BCdadd: genBinary(TR::dadd); _bcIndex += 1; break;388389case J9BCisub: genBinary(TR::isub); _bcIndex += 1; break;390case J9BClsub: genBinary(TR::lsub); _bcIndex += 1; break;391case J9BCfsub: genBinary(TR::fsub); _bcIndex += 1; break;392case J9BCdsub: genBinary(TR::dsub); _bcIndex += 1; break;393394case J9BCimul: genBinary(TR::imul); _bcIndex += 1; break;395case J9BClmul: genBinary(TR::lmul); _bcIndex += 1; break;396case J9BCfmul: genBinary(TR::fmul); _bcIndex += 1; break;397case J9BCdmul: genBinary(TR::dmul); _bcIndex += 1; break;398399case J9BCidiv: genIDiv(); _bcIndex += 1; break;400case J9BCldiv: genLDiv(); _bcIndex += 1; break;401402case J9BCirem: genIRem(); _bcIndex += 1; break;403case J9BClrem: genLRem(); _bcIndex += 1; break;404405case J9BCfdiv: genBinary(TR::fdiv); _bcIndex += 1; break;406case J9BCddiv: genBinary(TR::ddiv); _bcIndex += 1; break;407case J9BCfrem: genBinary(TR::frem); _bcIndex += 1; break;408case J9BCdrem: genBinary(TR::drem); _bcIndex += 1; break;409410case J9BCineg: genUnary(TR::ineg); _bcIndex += 1; break;411case J9BClneg: genUnary(TR::lneg); _bcIndex += 1; break;412case J9BCfneg: genUnary(TR::fneg); _bcIndex += 1; break;413case J9BCdneg: genUnary(TR::dneg); _bcIndex += 1; break;414415case J9BCishl: genBinary(TR::ishl); _bcIndex += 1; break;416case J9BCishr: genBinary(TR::ishr); _bcIndex += 1; break;417case J9BCiushr: genBinary(TR::iushr); _bcIndex += 1; break;418case J9BClshl: genBinary(TR::lshl); _bcIndex += 1; break;419case J9BClshr: genBinary(TR::lshr); _bcIndex += 1; break;420case J9BClushr: genBinary(TR::lushr); _bcIndex += 1; break;421422case J9BCiand: genBinary(TR::iand); _bcIndex += 1; break;423case J9BCior: genBinary(TR::ior); _bcIndex += 1; break;424case J9BCixor: genBinary(TR::ixor); _bcIndex += 1; break;425case J9BCland: genBinary(TR::land); _bcIndex += 1; break;426case J9BClor: genBinary(TR::lor); _bcIndex += 1; break;427case J9BClxor: genBinary(TR::lxor); _bcIndex += 1; break;428429case J9BCi2l: genUnary(TR::i2l); _bcIndex += 1; break;430case J9BCi2f: genUnary(TR::i2f); _bcIndex += 1; break;431case J9BCi2d: genUnary(TR::i2d); _bcIndex += 1; break;432433case J9BCl2i: genUnary(TR::l2i); _bcIndex += 1; break;434case J9BCl2f: genUnary(TR::l2f); _bcIndex += 1; break;435case J9BCl2d: genUnary(TR::l2d); _bcIndex += 1; break;436case J9BCf2i: genUnary(TR::f2i); _bcIndex += 1; break;437438case J9BCf2d: genUnary(TR::f2d); _bcIndex += 1; break;439case J9BCd2i: genUnary(TR::d2i); _bcIndex += 1; break;440case J9BCd2f: genUnary(TR::d2f); _bcIndex += 1; break;441case J9BCf2l: genUnary(TR::f2l); _bcIndex += 1; break;442case J9BCd2l: genUnary(TR::d2l); _bcIndex += 1; break;443444case J9BCi2b: genUnary(TR::i2b); genUnary(TR::b2i); _bcIndex += 1; break;445case J9BCi2c: genUnary(TR::i2s); genUnary(TR::su2i); _bcIndex += 1; break;446case J9BCi2s: genUnary(TR::i2s); genUnary(TR::s2i); _bcIndex += 1; break;447448case J9BCinvokevirtual: genInvokeVirtual(next2Bytes()); _bcIndex += 3; break;449case J9BCinvokespecial: genInvokeSpecial(next2Bytes()); _bcIndex += 3; break;450case J9BCinvokestatic: genInvokeStatic(next2Bytes()); _bcIndex += 3; break;451case J9BCinvokeinterface: genInvokeInterface(next2Bytes()); _bcIndex += 3; break;452case J9BCinvokedynamic:453genInvokeDynamic(next2Bytes());454_bcIndex += 3; break; // Could eventually need next3bytes455case J9BCinvokehandle:456genInvokeHandle(next2Bytes());457_bcIndex += 3; break;458case J9BCinvokehandlegeneric:459genInvokeHandleGeneric(next2Bytes());460_bcIndex += 3; break;461case J9BCinvokespecialsplit: genInvokeSpecial(next2Bytes() | J9_SPECIAL_SPLIT_TABLE_INDEX_FLAG); _bcIndex += 3; break;462case J9BCinvokestaticsplit: genInvokeStatic(next2Bytes() | J9_STATIC_SPLIT_TABLE_INDEX_FLAG); _bcIndex += 3; break;463464case J9BCifeq: _bcIndex = genIfOneOperand(TR::ificmpeq); break;465case J9BCifne: _bcIndex = genIfOneOperand(TR::ificmpne); break;466case J9BCiflt: _bcIndex = genIfOneOperand(TR::ificmplt); break;467case J9BCifge: _bcIndex = genIfOneOperand(TR::ificmpge); break;468case J9BCifgt: _bcIndex = genIfOneOperand(TR::ificmpgt); break;469case J9BCifle: _bcIndex = genIfOneOperand(TR::ificmple); break;470case J9BCifnull: _bcIndex = genIfOneOperand(TR::ifacmpeq); break;471case J9BCifnonnull: _bcIndex = genIfOneOperand(TR::ifacmpne); break;472473case J9BCificmpeq: _bcIndex = genIfTwoOperand(TR::ificmpeq); break;474case J9BCificmpne: _bcIndex = genIfTwoOperand(TR::ificmpne); break;475case J9BCificmplt: _bcIndex = genIfTwoOperand(TR::ificmplt); break;476case J9BCificmpge: _bcIndex = genIfTwoOperand(TR::ificmpge); break;477case J9BCificmpgt: _bcIndex = genIfTwoOperand(TR::ificmpgt); break;478case J9BCificmple: _bcIndex = genIfTwoOperand(TR::ificmple); break;479case J9BCifacmpeq: _bcIndex = genIfAcmpEqNe(TR::ifacmpeq); break;480case J9BCifacmpne: _bcIndex = genIfAcmpEqNe(TR::ifacmpne); break;481482case J9BClcmp: _bcIndex = cmp(TR::lcmp, _lcmpOps, lastIndex); break;483case J9BCfcmpl: _bcIndex = cmp(TR::fcmpl, _fcmplOps, lastIndex); break;484case J9BCfcmpg: _bcIndex = cmp(TR::fcmpg, _fcmpgOps, lastIndex); break;485case J9BCdcmpl: _bcIndex = cmp(TR::dcmpl, _dcmplOps, lastIndex); break;486case J9BCdcmpg: _bcIndex = cmp(TR::dcmpg, _dcmpgOps, lastIndex); break;487488case J9BCtableswitch: _bcIndex = genTableSwitch (); break;489case J9BClookupswitch: _bcIndex = genLookupSwitch(); break;490491case J9BCgoto: _bcIndex = genGoto(_bcIndex + next2BytesSigned()); break;492case J9BCgotow: _bcIndex = genGoto(_bcIndex + next4BytesSigned()); break;493494case J9BCmonitorenter: genMonitorEnter(); _bcIndex += 1; break;495case J9BCmonitorexit: genMonitorExit(false); _bcIndex += 1; break;496497case J9BCathrow: _bcIndex = genAThrow(); break;498case J9BCarraylength: genArrayLength(); _bcIndex += 1; break;499500case J9BCgetstatic: loadStatic(next2Bytes()); _bcIndex += 3; break;501case J9BCgetfield: loadInstance(next2Bytes()); _bcIndex += 3; break;502case J9BCputstatic: storeStatic(next2Bytes()); _bcIndex += 3; break;503case J9BCputfield: storeInstance(next2Bytes()); _bcIndex += 3; break;504505case J9BCcheckcast: genCheckCast(next2Bytes()); _bcIndex += 3; break;506case J9BCinstanceof: genInstanceof(next2Bytes()); _bcIndex += 3; break;507508case J9BCnew: genNew(next2Bytes()); _bcIndex += 3; break;509case J9BCnewarray: genNewArray(nextByte()); _bcIndex += 2; break;510case J9BCanewarray: genANewArray(next2Bytes()); _bcIndex += 3; break;511case J9BCmultianewarray: genMultiANewArray(next2Bytes(), _code[_bcIndex+3]); _bcIndex += 4; break;512513case J9BCiinc: genInc(); _bcIndex += 3; break;514case J9BCiincw: genIncLong(); _bcIndex += 5; break;515516case J9BCwide:517{518int32_t wopcode = _code[++_bcIndex];519TR_J9ByteCode wbc = convertOpCodeToByteCodeEnum(wopcode);520if (_bcIndex > lastIndex)521lastIndex = _bcIndex;522if (wbc == J9BCiinc)523{ genIncLong(); _bcIndex += 5; break; }524525switch (wbc)526{527case J9BCiload: loadAuto(TR::Int32, next2Bytes()); break;528case J9BClload: loadAuto(TR::Int64, next2Bytes()); break;529case J9BCfload: loadAuto(TR::Float, next2Bytes()); break;530case J9BCdload: loadAuto(TR::Double, next2Bytes()); break;531case J9BCaload: loadAuto(TR::Address, next2Bytes()); break;532533case J9BCistore: storeAuto(TR::Int32, next2Bytes()); break;534case J9BClstore: storeAuto(TR::Int64, next2Bytes()); break;535case J9BCfstore: storeAuto(TR::Float, next2Bytes()); break;536case J9BCdstore: storeAuto(TR::Double, next2Bytes()); break;537case J9BCastore: storeAuto(TR::Address, next2Bytes()); break;538default: break;539}540_bcIndex += 3;541break;542}543544case J9BCgenericReturn:545case J9BCReturnC:546case J9BCReturnS:547case J9BCReturnB:548case J9BCReturnZ:549_bcIndex = genReturn(method()->returnOpCode(), method()->isSynchronized());550break;551552case J9BCaconst_init:553{554if (TR::Compiler->om.areValueTypesEnabled())555{556genAconst_init(next2Bytes());557_bcIndex += 3;558}559else560{561fej9()->unsupportedByteCode(comp(), opcode);562}563break;564}565case J9BCwithfield:566if (TR::Compiler->om.areValueTypesEnabled())567{568genWithField(next2Bytes());569_bcIndex += 3;570}571else572{573fej9()->unsupportedByteCode(comp(), opcode);574}575break;576case J9BCbreakpoint:577fej9()->unsupportedByteCode(comp(), opcode);578case J9BCunknown:579fej9()->unknownByteCode(comp(), opcode);580break;581default:582break;583}584585if (comp()->getOption(TR_TraceILGen))586{587TR::StackMemoryRegion stackMemoryRegion(*comp()->trMemory());588589TR_BitVector beforeTreesInserted(comp()->getNodeCount(), trMemory(), stackAlloc, growable);590TR_BitVector afterTreesInserted (comp()->getNodeCount(), trMemory(), stackAlloc, growable);591592comp()->getDebug()->saveNodeChecklist(beforeTreesInserted);593printTrees(comp(), traceStart->getNextTreeTop(), traceStop, "trees inserted");594comp()->getDebug()->saveNodeChecklist(afterTreesInserted);595596// Commoning in the "stack after" printout should match that in the597// "trees inserted" printout.598//599// NOTE: this is disabled because it prints (potentially large) trees600// twice for no particular benefit. Instead, we have opted to have601// the "stack after" printout appear to be "commoned" with the "trees602// inserted" printout. This might cause some minor confusion when the603// "stack after" section contains nodes with refcount=1 that appear to604// be commoned, but this overall clarity seems to favour the terser format.605//606//comp()->getDebug()->restoreNodeChecklist(beforeTreesInserted);607printStack(comp(), _stack, "stack after");608609traceMsg(comp(), " ============================================================\n");610611// Commoning from now on will reflect trees already inserted, not612// those that happened to appear on the stack. (The desirability613// of the resulting verbosity is debatable.)614//615comp()->getDebug()->restoreNodeChecklist(afterTreesInserted);616}617}618619if( _blocksToInline) // partial inlining - only generate goto if its in the list of blocks.620{621if(_blocksToInline->getHighestBCIndex() > lastIndex)622{623lastIndex = _blocksToInline->getHighestBCIndex();624//printf("Walker: setting lastIndex to %d\n",lastIndex);625}626if(_blocksToInline->getLowestBCIndex() < firstIndex)627{628firstIndex = _blocksToInline->getLowestBCIndex();629//printf("Walker: setting firstIndex to %d\n",firstIndex);630}631}632633// join the basic blocks634//635TR::Block * lastBlock = NULL, * nextBlock, * block = blocks(firstIndex);636if (firstIndex == 0)637cfg()->addEdge(cfg()->getStart(), block);638else639prevBlock->getExit()->join(block->getEntry());640for (i = firstIndex; block; lastBlock = block, block = nextBlock)641{642while (block->getNextBlock())643{644TR_ASSERT( block->isAdded(), "Block should have already been added\n" );645block = block->getNextBlock();646}647648block->setIsAdded();649650for (nextBlock = 0; !nextBlock && ++i <= lastIndex; )651if (isGenerated(i) && blocks(i) && !blocks(i)->isAdded())652nextBlock = blocks(i);653654// If an exception range ends with an if and the fall through is655// in the main-line code then we have to generate a fall through block656// which contains a goto to jump back to the main-line code.657//658TR::Node * lastRealNode = block->getLastRealTreeTop()->getNode();659if (!nextBlock && lastRealNode->getOpCode().isIf())660{661nextBlock = TR::Block::createEmptyBlock(comp());662i = lastIndex;663if(_blocksToInline)664{665if(!blocks(i+3))666{667TR_ASSERT(_blocksToInline->hasGeneratedRestartTree(),"Fall Thru Block doesn't exist and we don't have a restart tree.\n");668nextBlock->append(669TR::TreeTop::create(comp(),670TR::Node::create(lastRealNode, TR::Goto, 0, _blocksToInline->getGeneratedRestartTree())));671}672else673{674nextBlock->append(675TR::TreeTop::create(comp(),676TR::Node::create(lastRealNode, TR::Goto, 0, blocks(i + 3)->getEntry())));677}678}679else680{681TR_ASSERT(blocks(i + 3), "can't find the fall thru block");682nextBlock->append(683TR::TreeTop::create(comp(),684TR::Node::create(lastRealNode, TR::Goto, 0, blocks(i + 3)->getEntry())));685}686}687block->getExit()->getNode()->copyByteCodeInfo(lastRealNode);688cfg()->insertBefore(block, nextBlock);689}690691if(_blocksToInline && _blocksToInline->hasGeneratedRestartTree())692{693_blocksToInline->getGeneratedRestartTree()->getEnclosingBlock()->setIsCold();694_blocksToInline->getGeneratedRestartTree()->getEnclosingBlock()->setFrequency(1);695}696697return lastBlock;698}699700//----------------------------------------------701// walker helper routines702//----------------------------------------------703704int32_t705TR_J9ByteCodeIlGenerator::cmp(TR::ILOpCodes cmpOpcode, TR::ILOpCodes * combinedOpcodes, int32_t & lastIndex)706{707int32_t nextBCIndex = _bcIndex + 1;708uint8_t nextOpcode = _code[nextBCIndex];709710// can't generate the async check here if someone is jumping to it711//712if (convertOpCodeToByteCodeEnum(nextOpcode) == J9BCasyncCheck && blocks(nextBCIndex) == 0)713{714genAsyncCheck();715nextBCIndex = ++_bcIndex + 1;716nextOpcode = _code[nextBCIndex];717if (_bcIndex > lastIndex)718lastIndex = _bcIndex;719}720721TR::ILOpCodes combinedOpcode;722switch (convertOpCodeToByteCodeEnum(nextOpcode))723{724case J9BCifeq: combinedOpcode = combinedOpcodes[0]; break;725case J9BCifne: combinedOpcode = combinedOpcodes[1]; break;726case J9BCiflt: combinedOpcode = combinedOpcodes[2]; break;727case J9BCifge: combinedOpcode = combinedOpcodes[3]; break;728case J9BCifgt: combinedOpcode = combinedOpcodes[4]; break;729case J9BCifle: combinedOpcode = combinedOpcodes[5]; break;730default: combinedOpcode = TR::BadILOp; break;731}732733// don't combine the opcodes if someone is jumping to the if734//735if (combinedOpcode != TR::BadILOp && blocks(nextBCIndex) == 0)736return cmpFollowedByIf(nextOpcode, combinedOpcode, lastIndex);737738genBinary(cmpOpcode);739genUnary(TR::b2i);740return _bcIndex + 1;741}742743int32_t744TR_J9ByteCodeIlGenerator::cmpFollowedByIf(uint8_t ifOpcode, TR::ILOpCodes combinedOpcode, int32_t & lastIndex)745{746int32_t branchOffset = next2BytesSigned(2); // The 2 bytes after the compare bytecode is the branch offset747748// If asynccheck is needed, generate it before incrementing _bcIndex such that it has the bytecode index of749// the compare bytecode.750if (branchOffset <= 0)751{752genAsyncCheck();753}754755if (++_bcIndex > lastIndex)756lastIndex = _bcIndex;757758return genIfImpl(combinedOpcode);759}760761//----------------------------------------------762// gen helper routines763//----------------------------------------------764765TR::SymbolReference *766TR_J9ByteCodeIlGenerator::placeholderWithDummySignature()767{768// Note: signatures should always be correct. Only call this to pass the769// result to something like genNodeAndPopChildren which will expand the770// signature properly.771if (comp()->getOption(TR_TraceMethodIndex))772traceMsg(comp(), "placeholderWithDummySignature using owning symbol M%p _methodSymbol: M%p\n", comp()->getJittedMethodSymbol(), _methodSymbol);773774// Note that we use comp()->getJittedMethodSymbol() instead of _methodSymbol here.775// The caller doesn't matter for this special method, and there's no need to make776// potentially hundreds of symbols for the same method.777//778return comp()->getSymRefTab()->methodSymRefFromName(comp()->getJittedMethodSymbol(), JSR292_ILGenMacros, JSR292_placeholder, JSR292_placeholderSig, TR::MethodSymbol::Static);779}780781TR::SymbolReference *782TR_J9ByteCodeIlGenerator::placeholderWithSignature(char *prefix, int prefixLength, char *middle, int middleLength, char *suffix, int suffixLength)783{784return symRefWithArtificialSignature(placeholderWithDummySignature(),785".#.#.#",786prefix, prefixLength,787middle, middleLength,788suffix, suffixLength);789}790791TR::SymbolReference *792TR_J9ByteCodeIlGenerator::symRefWithArtificialSignature(TR::SymbolReference *original, char *effectiveSigFormat, ...)793{794TR::StackMemoryRegion stackMemoryRegion(*comp()->trMemory());795796va_list args;797va_start(args, effectiveSigFormat);798char *effectiveSig = vartificialSignature(stackAlloc, effectiveSigFormat, args);799va_end(args);800801TR::SymbolReference *result = comp()->getSymRefTab()->methodSymRefWithSignature(original, effectiveSig, strlen(effectiveSig));802803return result;804}805806static int32_t processArtificialSignature(char *result, char *format, va_list args)807{808int32_t resultLength = 0;809char *cur = result;810for (int32_t i = 0; format[i]; i++)811{812int32_t length=-1;813char *startChar=NULL;814if (format[i] == '.') // period is the ONLY character (besides null) that can never appear in a method signature815{816// Formatting code817switch (format[++i])818{819case '@': // insert a single given arg out of a given signature820{821char *sig = va_arg(args, char*);822int n = va_arg(args, int);823startChar = nthSignatureArgument(n, sig+1);824length = nextSignatureArgument(startChar) - startChar;825break;826}827case '-': // insert a given range of args out of a given signature828{829char *sig = va_arg(args, char*);830int firstN = va_arg(args, int);831int lastN = va_arg(args, int);832if (lastN >= firstN)833{834startChar = nthSignatureArgument(firstN, sig+1);835length = nthSignatureArgument(lastN+1, sig+1) - startChar;836}837else838{839startChar = "";840length = 0;841}842break;843}844case '*': // insert args from a given one onward, out of a given signature845{846char *sig = va_arg(args, char*);847int firstN = va_arg(args, int);848startChar = nthSignatureArgument(firstN, sig+1);849length = strchr(startChar, ')') - startChar;850break;851}852case '$': // insert return type from a given signature853{854char *sig = va_arg(args, char*);855startChar = strchr(sig, ')') + 1;856length = nextSignatureArgument(startChar) - startChar;857break;858}859case '?': // insert a given null-terminated string860{861startChar = va_arg(args, char*);862length = strlen(startChar);863break;864}865case '#': // insert a given number of characters out of a given string866{867startChar = va_arg(args, char*);868length = va_arg(args, int);869break;870}871default: // literal character872TR_ASSERT(0, "Unexpected artificial signature formatting character '%c'", format[i]);873874// If we reach this point, either TR has a bug, or we have actually somehow875// encountered a signature that legitimately had a period in it. In the latter876// case, proceed on the assumption that the period was a literal character;877// if TR has a bug, we will very likely crash soon enough anyway.878//879startChar = format+i-1; // back up to the period880length = 2;881break;882}883}884else885{886// Literal character887startChar = format+i;888length = 1;889}890891TR_ASSERT(length >= 0, "assertion failure");892TR_ASSERT(startChar != NULL, "assertion failure");893894resultLength += length;895if (result)896cur += sprintf(cur, "%.*s", length, startChar);897898}899900return resultLength;901}902903char *TR_J9ByteCodeIlGenerator::artificialSignature(TR_AllocationKind allocKind, char *format, ...)904{905va_list args;906va_start(args, format);907char *result = vartificialSignature(allocKind, format, args);908va_end(args);909return result;910}911912char *TR_J9ByteCodeIlGenerator::vartificialSignature(TR_AllocationKind allocKind, char *format, va_list args)913{914// Compute size915//916va_list argsCopy;917va_copy(argsCopy, args);918int32_t resultLength = processArtificialSignature(NULL, format, argsCopy);919va_copy_end(argsCopy);920921// Produce formatted signature922//923char *result = (char*)trMemory()->allocateMemory(resultLength+1, allocKind);924processArtificialSignature(result, format, args);925return result;926}927928void929TR_J9ByteCodeIlGenerator::genArgPlaceholderCall()930{931// Create argument load nodes932//933int32_t numNodesGenerated = 0;934ListIterator<TR::ParameterSymbol> i(&_methodSymbol->getParameterList());935for (TR::ParameterSymbol *parm = i.getFirst(); parm; parm = i.getNext())936{937if (parm->getSlot() >= _argPlaceholderSlot)938{939// What a convoluted way to get a symref from a symbol...940TR::SymbolReference *symRef = _methodSymbol->getParmSymRef(parm->getSlot());941push(TR::Node::createLoad(symRef));942numNodesGenerated++;943}944}945946// Create placeholder call with the proper signature947//948char *callerSignature = _methodSymbol->getResolvedMethod()->signatureChars();949char *callerExpandedArgsStart = callerSignature + _argPlaceholderSignatureOffset;950int32_t lengthOfExpandedArgs = strcspn(callerExpandedArgsStart, ")");951TR::SymbolReference *placeholderSymRef = placeholderWithSignature("(", 1, callerExpandedArgsStart, lengthOfExpandedArgs, ")I", 2);952push(genNodeAndPopChildren(TR::icall, numNodesGenerated, placeholderSymRef));953}954955static bool isPlaceholderCall(TR::Node *node)956{957if (node->getOpCode().isCall() && node->getSymbol()->getResolvedMethodSymbol())958return node->getSymbol()->castToResolvedMethodSymbol()->getMandatoryRecognizedMethod() == TR::java_lang_invoke_ILGenMacros_placeholder;959else960return false;961}962963int32_t964TR_J9ByteCodeIlGenerator::expandPlaceholderCall()965{966TR::Node *placeholder = pop();967TR_ASSERT(isPlaceholderCall(placeholder), "expandPlaceholderCall expects placeholder call on top of stack");968if (comp()->getOption(TR_TraceILGen))969traceMsg(comp(), " Expanding placeholder call %s\n", comp()->getDebug()->getName(placeholder->getSymbolReference()));970for (int i = 0; i < placeholder->getNumChildren(); i++)971push(placeholder->getAndDecChild(i));972return placeholder->getNumChildren()-1; // there was already 1 for the placeholder itself973}974975TR::SymbolReference *976TR_J9ByteCodeIlGenerator::expandPlaceholderSignature(TR::SymbolReference *symRef, int32_t numArgs)977{978return expandPlaceholderSignature(symRef, numArgs, numArgs);979}980981TR::SymbolReference *982TR_J9ByteCodeIlGenerator::expandPlaceholderSignature(TR::SymbolReference *symRef, int32_t numArgs, int32_t firstArgStackDepth)983{984if (!symRef->getSymbol()->getResolvedMethodSymbol())985return symRef;986987TR_ResolvedMethod *originalMethod = symRef->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod();988989int32_t firstArgStackOffset = _stack->size() - firstArgStackDepth;990int32_t currentArgSignatureOffset = 1; // skip parenthesis991for (int32_t childIndex = originalMethod->isStatic()? 0 : 1; childIndex < numArgs; childIndex++)992{993int32_t explicitArgIndex = childIndex - (originalMethod->isStatic()? 0 : 1);994TR_ResolvedMethod *symRefMethod = symRef->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod();995char *signatureChars = symRefMethod->signatureChars();996int nextArgSignatureOffset = nextSignatureArgument(signatureChars + currentArgSignatureOffset) - signatureChars;997998TR_ASSERT(signatureChars[currentArgSignatureOffset] != ')', "expandPlaceholderSignature must not walk past the end of the argument portion of the signature");9991000TR::Node *child = _stack->element(firstArgStackOffset + childIndex);1001if (isPlaceholderCall(child))1002{1003// Replace the current argument's signature chars with the chars between the parentheses of the child's signature1004int32_t signatureLength = symRefMethod->signatureLength();1005char *childSignatureChars = child->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod()->signatureChars();1006int32_t numCharsInserted = strcspn(childSignatureChars+1, ")");1007symRef = symRefWithArtificialSignature(symRef,1008".#.#.#", // TODO:JSR292: It may be possible to simplify this logic drastically with a more clever format1009signatureChars, currentArgSignatureOffset,1010childSignatureChars+1, numCharsInserted,1011signatureChars+nextArgSignatureOffset, signatureLength - nextArgSignatureOffset);1012// This doesn't work...1013// "(-**)$",1014// symRefMethod->signatureChars(), 0, explicitArgIndex-1, // first n-1 args1015// childSignatureChars, 0, // child's args in place of current arg1016// symRefMethod->signatureChars(), explicitArgIndex+1, // last m args1017// symRefMethod->signatureChars() // return type1018// );1019currentArgSignatureOffset += numCharsInserted;1020}1021else1022{1023currentArgSignatureOffset = nextArgSignatureOffset;1024}1025}1026return symRef;1027}10281029int32_t1030TR_J9ByteCodeIlGenerator::numPlaceholderCalls(int32_t depthLimit)1031{1032int32_t result = 0;1033for (int32_t i = 0; i < depthLimit; i++)1034if (isPlaceholderCall(_stack->element(_stack->topIndex()-i)))1035result++;1036return result;1037}10381039int32_t1040TR_J9ByteCodeIlGenerator::expandPlaceholderCalls(int32_t depthLimit)1041{1042if (depthLimit <= 0)1043{1044return 0;1045}1046else1047{1048TR::Node *topNode = pop();1049int32_t numAdditionalNodes = expandPlaceholderCalls(depthLimit-1);1050push(topNode);1051if (isPlaceholderCall(_stack->element(_stack->topIndex())))1052numAdditionalNodes += expandPlaceholderCall();1053return numAdditionalNodes;1054}1055}10561057TR::Node *1058TR_J9ByteCodeIlGenerator::genNodeAndPopChildren(TR::ILOpCodes opcode, int32_t numChildren, TR::SymbolReference * symRef, int32_t firstIndex, int32_t lastIndex)1059{1060if (numPlaceholderCalls(lastIndex-firstIndex+1) > 0) // JSR2921061{1062symRef = expandPlaceholderSignature(symRef, lastIndex-firstIndex+1);1063int32_t numAdditionalNodes = expandPlaceholderCalls(lastIndex-firstIndex+1);1064numChildren += numAdditionalNodes;1065lastIndex += numAdditionalNodes;10661067if (comp()->getOption(TR_TraceILGen))1068{1069traceMsg(comp(), " Expanded placeholder(s) needing %d additional nodes -- resulting symref: %s\n", numAdditionalNodes, comp()->getDebug()->getName(symRef));10701071TR::StackMemoryRegion stackMemoryRegion(*comp()->trMemory());10721073TR_BitVector before(comp()->getNodeCount(), trMemory(), stackAlloc, growable);1074printStack(comp(), _stack, "stack after expandPlaceholderCalls");1075comp()->getDebug()->restoreNodeChecklist(before);1076}1077}10781079TR::Node * node = TR::Node::createWithSymRef(opcode, numChildren, symRef);1080for (int32_t i = lastIndex; i >= firstIndex; --i)1081node->setAndIncChild(i, pop());1082return node;1083}10841085TR::Node *1086TR_J9ByteCodeIlGenerator::genNodeAndPopChildren(TR::ILOpCodes opcode, int32_t numChildren, TR::SymbolReference * symRef, int32_t firstIndex)1087{1088return genNodeAndPopChildren(opcode, numChildren, symRef, firstIndex, numChildren-1);1089}10901091void1092TR_J9ByteCodeIlGenerator::genUnary(TR::ILOpCodes unaryOp, bool isForArrayAccess)1093{1094TR::Node *node = TR::Node::create(unaryOp, 1, pop());1095if(isForArrayAccess)1096{1097if (comp()->getOption(TR_TraceILGen))1098{1099traceMsg(comp(), "setting i2l node %p n%dn non-negative because it's for array access\n");1100}1101node->setIsNonNegative(true);1102}1103push(node);1104}11051106bool1107TR_J9ByteCodeIlGenerator::swapChildren(TR::ILOpCodes nodeop, TR::Node * firstChild)1108{1109return TR::ILOpCode(nodeop).getOpCodeForSwapChildren() &&1110(firstChild->getOpCode().isLoadConst() ||1111(firstChild->getOpCode().isLoadVar() && firstChild->getSymbol()->isConst()));1112}11131114void1115TR_J9ByteCodeIlGenerator::genBinary(TR::ILOpCodes nodeop, int32_t numChildren)1116{1117TR::Node * second = pop();1118TR::Node * first = pop();1119if (swapChildren(nodeop, first))1120push(TR::Node::create(TR::ILOpCode(nodeop).getOpCodeForSwapChildren(), numChildren, second, first));1121else1122push(TR::Node::create(nodeop, numChildren, first, second));1123}11241125TR::TreeTop *1126TR_J9ByteCodeIlGenerator::genTreeTop(TR::Node * n)1127{1128if (!n->getOpCode().isTreeTop())1129n = TR::Node::create(TR::treetop, 1, n);11301131//In involuntaryOSR, exception points are OSR points but we don't need to1132//handle pending pushes for them because the operand stack is always empty at catch.1133bool isExceptionOnlyPoint = comp()->getOSRMode() == TR::involuntaryOSR && !n->canGCandReturn() && n->canGCandExcept();1134if (comp()->getOption(TR_TraceOSR))1135traceMsg(comp(), "skip saving PPS for exceptionOnlyPoints %d node n%dn\n", isExceptionOnlyPoint, n->getGlobalIndex());11361137// It is not necessary to save the stack under OSR if the bytecode index or caller has been marked as cannotAttemptOSR1138bool cannotAttemptOSR = comp()->getOption(TR_EnableOSR) && !comp()->isPeekingMethod() &&1139(_methodSymbol->cannotAttemptOSRAt(n->getByteCodeInfo(), NULL, comp()) || _cannotAttemptOSR);1140if (comp()->getOption(TR_TraceOSR) && cannotAttemptOSR)1141traceMsg(comp(), "skip saving PPS for cannotAttemptOSR at %d:%d node n%dn\n", n->getByteCodeIndex(), n->getByteCodeInfo().getCallerIndex(), n->getGlobalIndex());11421143if (!comp()->isPeekingMethod() && comp()->isPotentialOSRPoint(n) && !isExceptionOnlyPoint && !cannotAttemptOSR)1144{1145static const char *OSRPPSThreshold;1146static int32_t osrPPSThresh = (OSRPPSThreshold = feGetEnv("TR_OSRPPSThreshold")) ? atoi(OSRPPSThreshold) : 0;1147static const char *OSRTotalPPSThreshold;1148static int32_t osrTotalPPSThresh = (OSRTotalPPSThreshold = feGetEnv("TR_OSRTotalPPSThreshold")) ? atoi(OSRTotalPPSThreshold) : 0;11491150static const char *OSRPPSThresholdOutsideLoops;1151static int32_t osrPPSThreshOutsideLoops = (OSRPPSThresholdOutsideLoops = feGetEnv("TR_OSRPPSThresholdOutsideLoops")) ? atoi(OSRPPSThresholdOutsideLoops) : 0;1152static const char *OSRTotalPPSThresholdOutsideLoops;1153static int32_t osrTotalPPSThreshOutsideLoops = (OSRTotalPPSThresholdOutsideLoops = feGetEnv("TR_OSRTotalPPSThresholdOutsideLoops")) ? atoi(OSRTotalPPSThresholdOutsideLoops) : 0;11541155static const char *OSRLoopNestingThreshold;1156static int32_t osrLoopNestingThresh = (OSRLoopNestingThreshold = feGetEnv("TR_OSRLoopNestingThreshold")) ? atoi(OSRLoopNestingThreshold) : 1;11571158static const char *OSRIndirectCallBCThreshold;1159static int32_t osrIndirectCallBCThresh = (OSRIndirectCallBCThreshold = feGetEnv("TR_OSRIndirectCallBCThreshold")) ? atoi(OSRIndirectCallBCThreshold) : 0;11601161bool OSRTooExpensive = false;1162if ((n->getNumChildren() > 0) && !comp()->getOption(TR_EnableOSROnGuardFailure) && comp()->getHCRMode() != TR::osr &&11631164(((comp()->getNumLoopNestingLevels() == 0) &&1165((((int32_t) _stack->size()) > osrPPSThreshOutsideLoops) || true ||1166((((int32_t) _stack->size() + (int32_t) comp()->getNumLivePendingPushSlots())) > osrTotalPPSThreshOutsideLoops))) ||11671168((comp()->getNumLoopNestingLevels() >= osrLoopNestingThresh) &&1169((((int32_t) _stack->size()) > osrPPSThresh) ||1170((((int32_t) _stack->size() + (int32_t) comp()->getNumLivePendingPushSlots())) > osrTotalPPSThresh))) ||11711172(n->getFirstChild()->getOpCode().isCallIndirect() &&1173(n->getFirstChild()->getSymbolReference()->isUnresolved() || true || // turned OSR off for indirect calls for 727 due to failed guards being seen1174n->getFirstChild()->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod()->virtualMethodIsOverridden() ||1175comp()->getPersistentInfo()->isClassLoadingPhase() ||1176(comp()->getOption(TR_EnableHCR) &&1177(!n->getFirstChild()->getSecondChild()->getOpCode().isLoadVarDirect() || !n->getFirstChild()->getSecondChild()->getSymbol()->isParm())) ||1178(n->getFirstChild()->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod()->maxBytecodeIndex() > osrIndirectCallBCThresh)))1179))1180{1181OSRTooExpensive = true;1182if (n->getFirstChild()->getOpCode().isCall() && !comp()->getOption(TR_FullSpeedDebug) && comp()->getOption(TR_EnableOSR))1183{1184if (comp()->getOption(TR_TraceOSR))1185traceMsg(comp(), "Skipping OSR due to cost at bci %d.%d\n", comp()->getCurrentInlinedSiteIndex(), n->getFirstChild()->getByteCodeIndex());1186_methodSymbol->setCannotAttemptOSR(n->getFirstChild()->getByteCodeIndex());1187}1188}11891190if ((comp()->getOption(TR_MimicInterpreterFrameShape) ||1191comp()->getOption(TR_FullSpeedDebug) ||1192comp()->getHCRMode() == TR::osr ||1193((n->getNumChildren() > 0) && n->getFirstChild()->getOpCode().isCall() && !OSRTooExpensive && comp()->getOption(TR_EnableOSR)))1194&& !comp()->isPeekingMethod())1195{1196if (comp()->isOSRTransitionTarget(TR::postExecutionOSR))1197{1198// When transitioning to a call bytecode, the VM requires that its1199// arguments be provided as children to the induce call1200// As the transition will occur at the next bytecode in post1201// execution, ensure the arguments for the next bytecode are1202// stashed1203//1204_couldOSRAtNextBC = true;1205if ((n->getOpCode().isCheck() || n->getOpCodeValue() == TR::treetop) && n->getFirstChild()->getOpCode().isCall())1206{1207// Calls are only OSR points for their first evaluation. Other references to the call,1208// that are also anchored under checks or treetops, are not OSR points. This can be1209// identified based on a node checklist, as the reference count may be unreliable.1210//1211if (!_processedOSRNodes->contains(n->getFirstChild()))1212{1213_processedOSRNodes->add(n->getFirstChild());12141215// The current stack should contain the current method's state prior to the call,1216// with the call's arguments popped off. If this call is later inlined, it may1217// contain an OSR transition. Therefore, it is necessary to save the current1218// method's state now, so that it is available when the transition is made.1219handlePendingPushSaveSideEffects(n);1220saveStack(-1);1221stashPendingPushLivenessForOSR();1222}1223else if (comp()->getOption(TR_TraceOSR))1224{1225traceMsg(comp(), "Skipping OSR stack state for repeated call n%dn in treetop n%dn\n", n->getFirstChild()->getGlobalIndex(), n->getGlobalIndex());1226}12271228return _block->append(TR::TreeTop::create(comp(), n));1229}1230else1231{1232// Save the stack after the treetop has been created and appended1233handlePendingPushSaveSideEffects(n);1234TR::TreeTop *toReturn = _block->append(TR::TreeTop::create(comp(), n));1235saveStack(-1, !comp()->pendingPushLivenessDuringIlgen());1236stashPendingPushLivenessForOSR(comp()->getOSRInductionOffset(n));12371238return toReturn;1239}1240}1241else1242{1243handlePendingPushSaveSideEffects(n);12441245// saveStack(-1) actually stores out the current PPS to the PPS save1246// region so that the FSD stackwalker can copy it to the VM frame as1247// part of decompilation1248//1249saveStack(-1);1250stashPendingPushLivenessForOSR();1251}1252}1253}1254return _block->append(TR::TreeTop::create(comp(), n));1255}12561257void1258TR_J9ByteCodeIlGenerator::removeIfNotOnStack(TR::Node *n)1259{1260startCountingStackRefs();1261n->incReferenceCount();1262n->recursivelyDecReferenceCount();1263stopCountingStackRefs();1264}12651266void1267TR_J9ByteCodeIlGenerator::popAndDiscard(int n)1268{1269TR_ASSERT(n >= 0, "Number of nodes to pop and discard must be non-negative");1270startCountingStackRefs();1271for (int i = 0; i < n; i++)1272pop()->recursivelyDecReferenceCount();1273stopCountingStackRefs();1274}12751276void1277TR_J9ByteCodeIlGenerator::discardEntireStack()1278{1279startCountingStackRefs();1280while (!_stack->isEmpty())1281pop()->recursivelyDecReferenceCount();1282// stack is empty, no need to stopCountingStackRefs()1283}12841285void1286TR_J9ByteCodeIlGenerator::startCountingStackRefs()1287{1288for (int i = 0; i < _stack->size(); i++)1289_stack->element(i)->incReferenceCount();1290}12911292void1293TR_J9ByteCodeIlGenerator::stopCountingStackRefs()1294{1295for (int i = 0; i < _stack->size(); i++)1296_stack->element(i)->decReferenceCount();1297}12981299// saveStack is called to save the operand stack, normally when it might1300// be live across BB (as in the call from genTarget). In addition, in1301// FSD mode, saveStack is sometimes called with no target block (with1302// targetIndex < 0), which means we're saving pending pop slots (PPS) at a1303// decompilation point (GC return point?) for FSD.1304//1305// In any case we store each operand stack/PPS (Pending Pop Stack) slot1306// to a region of the frame used exclusively for saving and restoring1307// PPS slots.1308//1309// if there is no PPS (Pending Pop Stack) for the target bytecode1310// (Which must be the first in the target bb) we create one which is1311// subsequently initialized with the current PPS. This is just a1312// lazy initialization.1313//1314// When a bb is translated _stackTemps initially is a copy of the1315// upwardly exposed operand stack to the current bb(?) Then, as slot i1316// is saved by this method _stackTemps[i] is set to the node1317// representing the value stored. This allows us to trivially avoid1318// redundantly saving the same slot over and over. (Presumably this is1319// primarily useful at decompilation points in FSD mode though it would1320// also avoid saving slots that flow through a block undisturbed.)1321//1322// The code below appears to save all PPS deeper than _stackTemp but1323// only those shallower which are not the same as the corresponding1324// slots in _stackTemp. Presumably this is because it is not necessary1325// to save a PPS that already must have been saved on entry to the1326// current block, ie: when (i <= _stackTemps.topIndex())1327//1328// Finally, when we are initializing a target block, we add the live1329// slots to the target bb's initial stack_. This is okay even if there1330// are multiple successors because the JVM spec requires that the1331// incoming PPS to each successor bb must be identical.1332//1333// int parm targetIndex indicates bytecode index of first op in the target bb.1334// bool parm anchorLoads will ensure any pending push temps that have not1335// been modified since the last call to saveStack will have the corresponding1336// pending push slot anchored1337//1338void1339TR_J9ByteCodeIlGenerator::saveStack(int32_t targetIndex)1340{1341saveStack(targetIndex, false);1342}13431344void1345TR_J9ByteCodeIlGenerator::saveStack(int32_t targetIndex, bool anchorLoads)1346{1347if (_stack->isEmpty())1348return;13491350static const char *disallowOSRPPS2 = feGetEnv("TR_DisallowOSRPPS2");1351bool loadPP = !disallowOSRPPS2 && comp()->getOption(TR_EnableOSR) && !comp()->isOSRTransitionTarget(TR::postExecutionOSR);1352bool createTargetStack = (targetIndex >= 0 && !_stacks[targetIndex]);1353if (createTargetStack)1354_stacks[targetIndex] = new (trStackMemory()) ByteCodeStack(trMemory(), std::max<uint32_t>(20, _stack->size()));13551356int32_t i;1357int32_t tempIndex = 0;1358for (i = 0; i < _stack->size(); ++i)1359{1360if (!isPlaceholderCall(_stack->element(i)))1361{1362if (_stackTemps.topIndex() < tempIndex || _stackTemps[tempIndex] != _stack->element(i))1363handlePendingPushSaveSideEffects(_stack->element(i), tempIndex);1364tempIndex++;1365}1366else1367{1368for (int32_t j = 0; j < _stack->element(i)->getNumChildren(); ++j)1369{1370TR::Node* child = _stack->element(i)->getChild(j);1371if (_stackTemps.topIndex() < tempIndex || _stackTemps[tempIndex] != child)1372handlePendingPushSaveSideEffects(child, tempIndex);1373tempIndex++;1374}1375}1376}13771378// There are three different indices here:1379// tempIndex: Index into stackTemps, which must take into account the additional children under placeholder calls1380// slot: The pending push slot, which must take into account the number of slots required by each node on the stack1381// i: Index into _stack1382//1383int32_t slot = 0;1384tempIndex = 0;1385for (i = 0; i < _stack->size(); ++i)1386{1387TR::Node * n = _stack->element(i);13881389if (!isPlaceholderCall(n))1390{1391TR::SymbolReference * symRef = symRefTab()->findOrCreatePendingPushTemporary(_methodSymbol, slot, getDataType(n));1392if (_stackTemps.topIndex() < tempIndex || _stackTemps[tempIndex] != n)1393{1394genTreeTop(TR::Node::createStore(symRef, n));13951396// Under preExecutionOSR, the stack elements are saved to pending push temps and then the corresponding1397// slots on the stack are replaced by loads of these temps. This ensures the pending push temp appears live1398// across any OSR points, due to the use of the load when it is popped off the stack.1399//1400if (loadPP)1401{1402TR::Node *load = TR::Node::createLoad(symRef);1403(*_stack)[i] = load;1404_stackTemps[tempIndex] = load;1405}1406else1407_stackTemps[tempIndex] = n;1408}14091410// Under postExecutionOSR, the stack elements are saved to pending push slots but the corresponding slots on the stack1411// are not modified. Instead, calls to saveStack where anchorLoads is true will achieve the same effect for liveness1412// by generating anchored loads of any pending push slots that have not been modified. There will be several superfluous1413// loads, but they can be cleaned up in genILOpts once the OSR liveness analysis is complete.1414//1415else if (anchorLoads1416&& comp()->getOption(TR_EnableOSR)1417&& comp()->isOSRTransitionTarget(TR::postExecutionOSR)1418&& _stackTemps[tempIndex] == n1419&& !(n->getOpCode().hasSymbolReference() && n->getSymbolReference() == symRef))1420genTreeTop(TR::Node::createLoad(symRef));14211422// this arranges that PPS i is reloaded on entry to the successor1423// basic block, which is the one starting at bytecode index targetIndex1424//1425if (createTargetStack)1426(*_stacks[targetIndex])[i] = TR::Node::createLoad(symRef);14271428slot += n->getNumberOfSlots();1429tempIndex++;1430}1431else1432{1433// A placeholder call has several children which represent the true contents of the stack1434// For correctness, these children should be stored into pending push slots1435//1436for (int32_t j = 0; j < n->getNumChildren(); ++j)1437{1438TR::Node* child = n->getChild(j);1439TR::SymbolReference * symRef = symRefTab()->findOrCreatePendingPushTemporary(_methodSymbol, slot, getDataType(child));1440if (_stackTemps.topIndex() < tempIndex || _stackTemps[tempIndex] != child)1441{1442genTreeTop(TR::Node::createStore(symRef, child));14431444if (loadPP)1445{1446TR::Node *load = TR::Node::createLoad(symRef);1447child->recursivelyDecReferenceCount();1448n->setAndIncChild(j, load);1449_stackTemps[tempIndex] = load;1450}1451else1452_stackTemps[tempIndex] = child;1453}1454else if (anchorLoads1455&& comp()->getOption(TR_EnableOSR)1456&& comp()->isOSRTransitionTarget(TR::postExecutionOSR)1457&& _stackTemps[tempIndex] == child1458&& !(child->getOpCode().hasSymbolReference() && child->getSymbolReference() == symRef))1459genTreeTop(TR::Node::createLoad(symRef));14601461slot += child->getNumberOfSlots();1462tempIndex++;1463}14641465// For this to be supported, pending push loads would always have to replace the placeholder's children in1466// all conditions1467TR_ASSERT_FATAL(!createTargetStack, "Cannot store and later load placeholder calls in current implementation");1468}1469}1470}14711472// Bad code results if code following saveStack generated stores1473// attempts to load from one of the saved PPS slots. Two obvious1474// examples arise. For the first example see the comment before1475// TR_J9ByteCodeIlGenerator::genIfImp. Second, consider a treetop preceding a1476// decompilation point. Nodes loaded from the PPS save region (i.e that1477// were live on entry to the block) may be referred to by treetops on1478// both sides of the decompilation point and thus may be killed by the1479// stores (soon to be) generated by saveStack.1480//1481// In both these scenarios the problem is that saveStack assumes the1482// execution mode of bytecode rather than the TR IL. The saveStack1483// method simply walks the simulated operand stack and generates a1484// store treetop for each Node it finds on the simulated stack. This,1485// like bytecode, assumes that operations are completed at the time1486// values are pushed on the simulated stack.1487//1488// Meanwhile, TR IL is being generated that refers to Nodes popped off1489// the stack. The assumption here is that the order of operations is1490// unconstrained other than by the data flow implied by the trees of1491// references to nodes and by the control dependencies imposed by the1492// order of treetops. The latter are implied by the semantics of each1493// bytecode.1494//1495// The job of handlePendingPushSaveSideEffects is to add additional1496// implicit control dependencies to the TR IL caused by the1497// decompilation points. All loads of the PPS save region must occur1498// before decompilation points except in the specific case when the load1499// would redundantly reload a value already in the PPS.1500//1501// If handlePendingPushSaveSideEffects is being called on the stack1502// contents in saveStack, before they are stored in to pending push temps,1503// it is possible to eliminate some of the excess anchored pending push1504// loads generated by this function using the stackSize parm. As1505// the pending pushes are modified in ascending order, it is safe to assume1506// any pending push slots equal to the current stack slot or greater have1507// not yet been stored to and are, therefore, safe to load from.1508//1509void1510TR_J9ByteCodeIlGenerator::handlePendingPushSaveSideEffects(TR::Node * n, int32_t stackSize)1511{1512if (_stack->size() == 0)1513return;15141515TR::NodeChecklist checklist(comp());1516handlePendingPushSaveSideEffects(n, checklist, stackSize);1517}15181519void1520TR_J9ByteCodeIlGenerator::handlePendingPushSaveSideEffects(TR::Node * n, TR::NodeChecklist &checklist, int32_t stackSize)1521{1522if (checklist.contains(n))1523return;1524checklist.add(n);15251526// if any tree on the stack can be modified by the sideEffect then the node1527// on the stack must become a treetop before the sideEffect node is evaluated1528//1529for (int32_t i = n->getNumChildren() - 1; i >= 0; --i)1530handlePendingPushSaveSideEffects(n->getChild(i), checklist, stackSize);15311532// constant pool indices less than 0 indicate loads from saved pending1533// pop slot locations. In addition, the value is the negation of the1534// PPS slot number the load is to.1535//1536if (n->getOpCode().isLoadVarDirect() && n->getSymbolReference()->isTemporary(comp()) && n->getSymbolReference()->getCPIndex() < 0)1537{1538// loadSlot: the pending push slot being loaded from1539int32_t loadSlot = -n->getSymbolReference()->getCPIndex() - 1;1540// absStackSlot: index into stack elements, taking placeholder children into account1541int32_t absStackSlot = 0;1542// child: keep track of placeholder children if necessary1543int32_t child = -1;1544// modifiedSlot: iterate through the slots currently in use1545int32_t modifiedSlot = 0;1546// i: iterate through the stack elements1547int32_t i = 0;1548for (i = 0; i < _stack->size(); ++i)1549{1550if (!isPlaceholderCall(_stack->element(i)))1551{1552if (modifiedSlot >= loadSlot)1553{1554child = -1;1555break;1556}1557modifiedSlot += _stack->element(i)->getNumberOfSlots();1558absStackSlot++;1559}1560else1561{1562for (child = 0; child < _stack->element(i)->getNumChildren(); ++child)1563{1564if (modifiedSlot >= loadSlot)1565break;1566modifiedSlot += _stack->element(i)->getChild(child)->getNumberOfSlots();1567absStackSlot++;1568}1569if (child < _stack->element(i)->getNumChildren())1570break;1571}1572}15731574// If there is a node on the stack that has uses the same slot, it could result in the pending push temp1575// being modified when the stack is saved, so it is anchored1576//1577if (modifiedSlot == loadSlot1578&& (stackSize == -1 || stackSize > absStackSlot)1579&& i < _stack->size()1580&& ((child >= 0 && _stack->element(i)->getChild(child) != n) || (child == -1 && _stack->element(i) != n)))1581{1582genTreeTop(n);1583}1584}1585}15861587bool1588TR_J9ByteCodeIlGenerator::isAtBBStart(int32_t bcIndex)1589{1590return blocks(bcIndex) && blocks(bcIndex)->getEntry()->getNode()->getByteCodeIndex() == bcIndex;1591}1592/*1593* Stash the required number of arguments for the provided bytecode.1594* The current stack will be walked, determining pending push temps for1595* the required arguments. It is assumed that the arguments would have1596* already been stored to these symrefs.1597*/1598void1599TR_J9ByteCodeIlGenerator::stashArgumentsForOSR(TR_J9ByteCode byteCode)1600{1601if (!_couldOSRAtNextBC &&1602!isAtBBStart(_bcIndex)) // _couldOSRAtNextBC doesn't work if the curent bc is at bbstart,1603// conversatively assume OSR transition can happen at bbstart1604return;1605_couldOSRAtNextBC = false;16061607if (comp()->isPeekingMethod()1608|| !comp()->getOption(TR_EnableOSR)1609|| _cannotAttemptOSR1610|| !comp()->isOSRTransitionTarget(TR::postExecutionOSR))1611return;16121613// Determine the symref to extract the number of arguments required by this bytecode1614TR::SymbolReference *symRef;1615// Check if cp entry is resolved, used by invokedynamic and invokehandle in OpenJDK MethodHandle implementation1616bool unresolvedInCP = false;1617switch (byteCode)1618{1619case J9BCinvokevirtual:1620symRef = symRefTab()->findOrCreateVirtualMethodSymbol(_methodSymbol, next2Bytes());1621break;1622case J9BCinvokespecial:1623symRef = symRefTab()->findOrCreateSpecialMethodSymbol(_methodSymbol, next2Bytes());1624break;1625case J9BCinvokestatic:1626symRef = symRefTab()->findOrCreateStaticMethodSymbol(_methodSymbol, next2Bytes());1627break;1628case J9BCinvokeinterface:1629symRef = symRefTab()->findOrCreateInterfaceMethodSymbol(_methodSymbol, next2Bytes());1630break;1631case J9BCinvokeinterface2:1632symRef = symRefTab()->findOrCreateInterfaceMethodSymbol(_methodSymbol, next2Bytes(3));1633break;1634case J9BCinvokedynamic:1635symRef = symRefTab()->findOrCreateDynamicMethodSymbol(_methodSymbol, next2Bytes(), &unresolvedInCP);1636break;1637case J9BCinvokehandle:1638case J9BCinvokehandlegeneric:1639symRef = symRefTab()->findOrCreateHandleMethodSymbol(_methodSymbol, next2Bytes(), &unresolvedInCP);1640break;1641case J9BCinvokestaticsplit:1642symRef = symRefTab()->findOrCreateStaticMethodSymbol(_methodSymbol, next2Bytes() | J9_STATIC_SPLIT_TABLE_INDEX_FLAG);1643break;1644case J9BCinvokespecialsplit:1645symRef = symRefTab()->findOrCreateSpecialMethodSymbol(_methodSymbol, next2Bytes() | J9_SPECIAL_SPLIT_TABLE_INDEX_FLAG);1646break;1647default:1648return;1649}16501651TR::MethodSymbol *symbol = symRef->getSymbol()->castToMethodSymbol();1652int32_t numArgs = symbol->getMethod()->numberOfExplicitParameters() + (symbol->isStatic() ? 0 : 1);16531654#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)1655// If the transition target is invokehandle/invokedynamic, the arguments to be1656// stashed are those already pushed onto the stack before generating the bytecode,1657// regardless of the number of arguments needed by the generated call.1658//1659// The generated call requires one (in resolved case) or two (in unresolved case)1660// implicit arguments, so we need to substract them to get the actual number of1661// arguments needed.1662// The reason why we don't need to stash the implicit arguments is because when we1663// transition to the VM, VM will push the implicit argument onto the stack, this is1664// part of the behavior of the invokehandle/invokedynamic bytecode.1665//1666// The method to call is determined by the MemberName object from the side table.1667// In the resolved case, one implicit object is passed as the last argument to the1668// call, it is the appendixObject from side table.1669//1670// When the side table entry is unresolved, this object is unknown, thus, the JIT1671// doesn't know what method to call at compile time. To represent the unresolved1672// case, the JIT uses MethodHandle.linkToStatic to represent the call.1673// In addtion to the appendixObject, the MemberName object is also needed, thus1674// the call requires two more arguments that what's on the stack.1675//1676// Resolved case:1677// adapter(arg1, arg2, ..., argN, appendixObject)1678// Unresolved case:1679// MethodHandle.linkToStatic(arg1, arg2, ..., argN, appendixObject, MemberName)1680//1681// Notice that we always generate a resolved call, thus we use unresolvedInCP to tell1682// us whether the side table entry is resolved1683//1684if (byteCode == J9BCinvokedynamic ||1685byteCode == J9BCinvokehandle)1686{1687numArgs -= 1;1688if (unresolvedInCP)1689numArgs -= 1;16901691if (trace())1692traceMsg(comp(), "Num args %d for invokedynamic/handle, stack size %d\n", numArgs, _stack->size());1693}1694#endif16951696TR_OSRMethodData *osrMethodData =1697comp()->getOSRCompilationData()->findOrCreateOSRMethodData(comp()->getCurrentInlinedSiteIndex(), _methodSymbol);1698osrMethodData->ensureArgInfoAt(_bcIndex, numArgs);16991700// Walk the stack, grabbing that last numArgs elements1701// It is necessary to walk the whole stack to determine the slot numbers1702int32_t slot = 0;1703int arg = 0;1704for (int32_t i = 0; i < _stack->size(); ++i)1705{1706TR::Node * n = _stack->element(i);1707if (_stack->size() - numArgs <= i)1708{1709TR::SymbolReference * symRef = symRefTab()->findOrCreatePendingPushTemporary(_methodSymbol, slot, getDataType(n));1710osrMethodData->addArgInfo(_bcIndex, arg, symRef->getReferenceNumber());1711arg++;1712}1713slot += n->getNumberOfSlots();1714}1715}17161717// Under voluntary OSR, it is preferable to keep only the essential symrefs live1718// for the transition. Computing the liveness can be costly however. To reduce1719// this compile time overhead, pending push liveness can be solved during IlGen.1720//1721// This method will solve the liveness for the current bci with the offset applied1722// and stash the result against the OSR method data.1723void1724TR_J9ByteCodeIlGenerator::stashPendingPushLivenessForOSR(int32_t offset)1725{1726if (!comp()->pendingPushLivenessDuringIlgen())1727return;17281729TR_OSRMethodData *osrData = comp()->getOSRCompilationData()->findOrCreateOSRMethodData(1730comp()->getCurrentInlinedSiteIndex(), comp()->getMethodSymbol());17311732// Reset any existing pending push mapping1733// This is due to the overlap with arg stashing1734TR_BitVector *livePP = osrData->getPendingPushLivenessInfo(_bcIndex + offset);1735if (livePP)1736livePP->empty();17371738int32_t slot = 0;1739int arg = 0;1740for (int32_t i = 0; i < _stack->size(); ++i)1741{1742TR::Node *n = _stack->element(i);1743TR::SymbolReference *symRef = symRefTab()->findOrCreatePendingPushTemporary(_methodSymbol, slot, getDataType(n));1744if (livePP)1745livePP->set(symRef->getReferenceNumber());1746else1747{1748livePP = new (trHeapMemory()) TR_BitVector(0, trMemory(), heapAlloc);1749livePP->set(symRef->getReferenceNumber());1750osrData->addPendingPushLivenessInfo(_bcIndex + offset, livePP);1751}1752slot += n->getNumberOfSlots();1753}1754}17551756void1757TR_J9ByteCodeIlGenerator::handleSideEffect(TR::Node * sideEffect)1758{1759// if any tree on the stack can be modified by the sideEffect then the node1760// on the stack must become a treetop before the sideEffect node is evaluated1761//1762for (int32_t i = 0; i < _stack->size(); ++i)1763{1764TR::Node * n = _stack->element(i);1765if (n->getReferenceCount() == 0 && valueMayBeModified(sideEffect, n))1766genTreeTop(n);1767}1768}17691770bool1771TR_J9ByteCodeIlGenerator::valueMayBeModified(TR::Node * sideEffect, TR::Node * node)1772{1773if (isPlaceholderCall(node))1774return false; // Placeholders have no side-effects17751776if (node->getOpCode().hasSymbolReference() && sideEffect->mayModifyValue(node->getSymbolReference()))1777return true;17781779int32_t numChilds = node->getNumChildren();1780for (int32_t i = 0; i < numChilds; ++i)1781if (valueMayBeModified(sideEffect, node->getChild(i)))1782return true;17831784return false;1785}178617871788TR::Node *1789TR_J9ByteCodeIlGenerator::loadConstantValueIfPossible(TR::Node *topNode, uintptr_t topFieldOffset, TR::DataType type, bool isArrayLength)1790{1791TR::Node *constNode = NULL;1792TR::Node *parent = topNode;1793TR::SymbolReference *symRef = NULL;1794uintptr_t fieldOffset = 0;1795if (topNode->getOpCode().hasSymbolReference())1796{1797symRef = topNode->getSymbolReference();1798if (symRef->getSymbol()->isShadow() &&1799symRef->getSymbol()->isFinal() &&1800!symRef->isUnresolved())1801{1802fieldOffset = symRef->getOffset();1803TR::Node *child = topNode->getFirstChild();1804if (child->getOpCode().hasSymbolReference())1805{1806topNode = child;1807symRef = child->getSymbolReference();1808}1809}1810}18111812if (symRef && symRef->getSymbol()->isStatic() && !symRef->isUnresolved() && symRef->getSymbol()->isFinal() && !symRef->getSymbol()->isConstObjectRef() && _method->isSameMethod(symRef->getOwningMethod(comp())))1813{1814TR::StaticSymbol *symbol = symRef->getSymbol()->castToStaticSymbol();1815TR_J9VMBase *fej9 = (TR_J9VMBase *)fe();181618171818bool isResolved = !symRef->isUnresolved();1819TR_OpaqueClassBlock * classOfStatic = isResolved ? _method->classOfStatic(topNode->getSymbolReference()->getCPIndex()) : 0;1820if (classOfStatic == NULL)1821{1822int len = 0;1823char * classNameOfFieldOrStatic = NULL;1824classNameOfFieldOrStatic = symRef->getOwningMethod(comp())->classNameOfFieldOrStatic(symRef->getCPIndex(), len);1825if (classNameOfFieldOrStatic)1826{1827classNameOfFieldOrStatic = TR::Compiler->cls.classNameToSignature(classNameOfFieldOrStatic, len, comp());1828TR_OpaqueClassBlock * curClass = fej9->getClassFromSignature(classNameOfFieldOrStatic, len, symRef->getOwningMethod(comp()));1829TR_OpaqueClassBlock * owningClass = comp()->getJittedMethodSymbol()->getResolvedMethod()->containingClass();1830if (owningClass == curClass)1831classOfStatic = curClass;1832}1833}18341835bool isClassInitialized = false;1836TR_PersistentClassInfo * classInfo = _noLookahead ? 0 :1837comp()->getPersistentInfo()->getPersistentCHTable()->findClassInfoAfterLocking(classOfStatic, comp());1838if (classInfo && classInfo->isInitialized())1839isClassInitialized = true;18401841bool canOptimizeFinalStatic = false;1842if (isResolved && symbol->isFinal() && !symRef->isUnresolved() &&1843classOfStatic != comp()->getSystemClassPointer() &&1844isClassInitialized)1845{1846//if (symbol->getDataType() == TR::Address)1847{1848// todo: figure out why classInfo would be NULL here?1849if (!classInfo->getFieldInfo())1850performClassLookahead(classInfo);1851}18521853if (classInfo->getFieldInfo() && !classInfo->cannotTrustStaticFinal())1854canOptimizeFinalStatic = true;1855}18561857if (canOptimizeFinalStatic)1858{1859TR::VMAccessCriticalSection loadConstantValueCriticalSection(fej9,1860TR::VMAccessCriticalSection::tryToAcquireVMAccess,1861comp());18621863if (loadConstantValueCriticalSection.hasVMAccess())1864{1865uintptr_t objectPointer = comp()->fej9()->getStaticReferenceFieldAtAddress((uintptr_t)symbol->getStaticAddress());1866if (objectPointer)1867{1868switch (symbol->getDataType())1869{1870case TR::Address:1871{1872if (parent != topNode)1873objectPointer = fej9->getReferenceFieldAt(objectPointer, fieldOffset);1874if ((type == TR::Int32) ||1875(type == TR::Int16) ||1876(type == TR::Int8))1877{1878int32_t val;1879if (isArrayLength)1880val = (int32_t)(fej9->getArrayLengthInElements(objectPointer));1881else1882val = *(int32_t*)(objectPointer + topFieldOffset);1883loadConstant(TR::iconst, val);1884constNode = _stack->top();1885}1886else if (type == TR::Int64)1887{1888int64_t val;1889if (isArrayLength)1890val = (int64_t)(fej9->getArrayLengthInElements(objectPointer));1891else1892val = *(int64_t*)(objectPointer + topFieldOffset);1893loadConstant(TR::lconst, val);1894constNode = _stack->top();1895}1896break;1897}1898default:1899break;1900}1901}1902}19031904} // VM Access Critical Section19051906}19071908return constNode;1909}19101911/**1912* @brief Abort compilation due to unsupported unresolved value type operation1913*1914* When dealing with unreslved CP references, certain value type operations cannot1915* be handled. This helper provides a convenient way of aborting the compilation1916* in such cases.1917*1918* The abort is triggered by throwing TR::UnsupportedValueTypeOperation with an1919* appropriate exception message.1920*1921* Static debug counters are also used to keep track of how frequently these1922* aborts occure. The counters are named using the following formats:1923*1924* - for outermost methods: ilgen.abort/unresolved/{bytecodeName}/{refType}/({method signature})/bc={bcIndex}1925* - for inlining/peeking: ilgen.abort/unresolved/{bytecodeName}/{refType}/({method signature})/bc={bcIndex}/root=({top level method signature})1926*1927* @param bytecodeName is the name of the unhandled bytecode instruction1928* @param refType is the type of unresolved reference (e.g. field, class, etc.)1929* @throw TR::UnsupportedValueTypeOperation unconditionally1930*/1931void1932TR_J9ByteCodeIlGenerator::abortForUnresolvedValueTypeOp(const char* bytecodeName, const char* refType)1933{1934const int32_t bcIndex = currentByteCodeIndex();1935if (isOutermostMethod())1936{1937TR::DebugCounter::incStaticDebugCounter(comp(),1938TR::DebugCounter::debugCounterName(comp(),1939"ilgen.abort/unresolved/%s/%s/(%s)/bc=%d",1940bytecodeName,1941refType,1942comp()->signature(),1943bcIndex));1944}1945else1946{1947TR::DebugCounter::incStaticDebugCounter(comp(),1948TR::DebugCounter::debugCounterName(comp(),1949"ilgen.abort/unresolved/%s/%s/(%s)/bc=%d/root=(%s)",1950bytecodeName,1951refType,1952_method->signature(comp()->trMemory()),1953bcIndex,1954comp()->signature()));1955}19561957comp()->failCompilation<TR::UnsupportedValueTypeOperation>("Unresolved %s encountered for %s bytecode instruction", refType, bytecodeName);1958}19591960//----------------------------------------------1961// gen array1962//----------------------------------------------1963void1964TR_J9ByteCodeIlGenerator::genArrayLength()1965{1966TR::Node * node = NULL;1967TR::Node * topNode = pop();19681969TR::Node *loadedConst = loadConstantValueIfPossible(topNode, fej9()->getOffsetOfContiguousArraySizeField());19701971if (!loadedConst)1972{1973if ( comp()->cg()->getDisableNullCheckOfArrayLength() )1974node = TR::Node::create(TR::PassThrough, 1, topNode);1975else1976node = TR::Node::create(TR::arraylength, 1, topNode);19771978genTreeTop(genNullCheck(node));19791980if ( comp()->cg()->getDisableNullCheckOfArrayLength() )1981{1982node = TR::Node::create(TR::arraylength, 1, topNode);1983}19841985push(node);1986}1987}19881989void1990TR_J9ByteCodeIlGenerator::genContiguousArrayLength(int32_t width)1991{1992TR::Node * node = NULL;1993TR::Node * topNode = pop();19941995TR::Node *loadedConst = loadConstantValueIfPossible(topNode, fej9()->getOffsetOfContiguousArraySizeField());19961997// Discontiguous arrays still require the contiguity check and can't be folded.1998//1999if (loadedConst)2000{2001if (TR::Compiler->om.isDiscontiguousArray(loadedConst->getInt(), width))2002{2003pop();2004loadedConst = NULL;2005}2006}20072008if (!loadedConst)2009{2010if ( comp()->cg()->getDisableNullCheckOfArrayLength() )2011node = TR::Node::create(TR::PassThrough, 1, topNode);2012else2013node = TR::Node::create(TR::contigarraylength, 1, topNode);20142015genTreeTop(genNullCheck(node));20162017if ( comp()->cg()->getDisableNullCheckOfArrayLength() )2018{2019node = TR::Node::create(TR::contigarraylength, 1, topNode);2020}20212022push(node);2023}2024}20252026void2027TR_J9ByteCodeIlGenerator::genArrayBoundsCheck(TR::Node * offset, int32_t width)2028{2029bool canSkipThisBoundCheck = false;2030bool canSkipThisNullCheck = false;2031bool canSkipArrayLengthCalc = false;2032int32_t firstDimension = -1;20332034if (_classInfo)2035{2036if (!_classInfo->getFieldInfo())2037performClassLookahead(_classInfo);20382039// note: findFieldInfo may change baseArray2040TR::Node * baseArray = _stack->top();2041TR_PersistentFieldInfo * fieldInfo = _classInfo->getFieldInfo() ? _classInfo->getFieldInfo()->findFieldInfo(comp(), baseArray, true) : NULL;2042if (fieldInfo)2043{2044int32_t relevantDimension = _stack->top() == baseArray ? 0 : 1;2045TR_PersistentArrayFieldInfo *arrayFieldInfo = fieldInfo ? fieldInfo->asPersistentArrayFieldInfo() : 0;2046if (arrayFieldInfo && arrayFieldInfo->isDimensionInfoValid() &&2047arrayFieldInfo->getDimensionInfo(relevantDimension) >= 0)2048{2049firstDimension = arrayFieldInfo->getDimensionInfo(relevantDimension);20502051/*2052* When hybrid arraylets are used, simplification based on the arraylength can only2053* be done if the arraylength fits within a single region. Otherwise, a spine check2054* is still required.2055*/20562057if (!TR::Compiler->om.useHybridArraylets() || !TR::Compiler->om.isDiscontiguousArray(firstDimension, width))2058{2059if (performTransformation(comp(), "O^O CLASS LOOKAHEAD: Can skip array length calculation for array %p based on class file examination\n", baseArray))2060canSkipArrayLengthCalc = true;2061}20622063if (performTransformation(comp(), "O^O CLASS LOOKAHEAD: Can skip null check for array %p based on class file examination\n", baseArray))2064canSkipThisNullCheck = true;20652066if (offset->getOpCode().isLoadConst() &&2067offset->getDataType() == TR::Int32 &&2068offset->getInt() < firstDimension &&2069offset->getInt() >= 0 &&2070(!TR::Compiler->om.useHybridArraylets() || !TR::Compiler->om.isDiscontiguousArray(firstDimension, width)))2071{2072if (performTransformation(comp(), "O^O CLASS LOOKAHEAD: Can skip bound check for access %p using array %p which has length %d based on class file examination\n", offset, baseArray, firstDimension))2073canSkipThisBoundCheck = true;2074}2075}2076}2077}20782079if (comp()->requiresSpineChecks() || (!_methodSymbol->skipBoundChecks() && !canSkipThisBoundCheck))2080{2081TR::Node *arrayLength = 0;2082if (!canSkipArrayLengthCalc)2083{2084if (!comp()->requiresSpineChecks())2085genArrayLength();2086else2087genContiguousArrayLength(width);20882089arrayLength = pop();2090if (arrayLength->getOpCode().isArrayLength())2091arrayLength->setArrayStride(width);2092}2093else2094{2095TR_J9ByteCodeIteratorWithState::pop();2096arrayLength = TR::Node::create(TR::iconst, 0, firstDimension);2097}20982099if (comp()->requiresSpineChecks() && !_suppressSpineChecks)2100{2101// Create an incomplete check node that will be populated when all the children2102// are known. It must be created here to be sure it is anchored in the right spot.2103//2104TR::Node *checkNode = TR::Node::createWithSymRef(TR::BNDCHKwithSpineCHK, 4, 2, arrayLength, offset,2105symRefTab()->findOrCreateArrayBoundsCheckSymbolRef(_methodSymbol));21062107genTreeTop(checkNode);2108push(checkNode);2109swap();2110}2111else2112{2113genTreeTop(TR::Node::createWithSymRef(TR::BNDCHK, 2, 2, arrayLength, offset,2114symRefTab()->findOrCreateArrayBoundsCheckSymbolRef(_methodSymbol)));2115}2116}2117else2118{21192120offset->setIsNonNegative(true);21212122if (!_methodSymbol->skipNullChecks() && !canSkipThisNullCheck)2123{2124TR::Node * node = TR::Node::create(TR::PassThrough,1,pop());2125genTreeTop(genNullCheck(node));2126}2127else2128{2129TR_J9ByteCodeIteratorWithState::pop();2130}21312132// Create an incomplete check node that will be populated when all the children2133// are known. It must be created here to be sure it is anchored in the right spot.2134//2135if (comp()->requiresSpineChecks() && !_suppressSpineChecks)2136{2137TR::Node *spineChk = TR::Node::create(TR::SpineCHK, 3, offset);2138genTreeTop(spineChk);2139push(spineChk);2140swap();2141}2142else2143{2144genTreeTop(TR::Node::create(TR::treetop, 1, offset));2145}2146}21472148push(offset);2149}21502151// Helper to calculate the address of the array element in a contiguous array2152// Stack: ..., array base address, array element index2153// width is the width of each array element in bytes2154// headerSize is the number of header bytes at the beginning of the array2155void2156TR_J9ByteCodeIlGenerator::calculateElementAddressInContiguousArray(int32_t width, int32_t headerSize)2157{2158const bool isForArrayAccess = true;2159int32_t shift = TR::TransformUtil::convertWidthToShift(width);2160if (shift)2161{2162loadConstant(TR::iconst, shift);2163// generate a TR::aladd instead if required2164if (comp()->target().is64Bit())2165{2166// stack is now ...index,shift<===2167TR::Node *second = pop();2168genUnary(TR::i2l, isForArrayAccess);2169push(second);2170genBinary(TR::lshl);2171}2172else2173genBinary(TR::ishl);2174}2175if (comp()->target().is64Bit())2176{2177if (headerSize > 0)2178{2179loadConstant(TR::lconst, (int64_t)headerSize);2180// shift could have been null here (if no scaling is done for the index2181// ...so check for that and introduce an i2l if required for the aladd2182// stack now is ....index,loadConst<===2183if (!shift)2184{2185TR::Node *second = pop();2186genUnary(TR::i2l, isForArrayAccess);2187push(second);2188}2189genBinary(TR::ladd);2190}2191else if ((headerSize == 0) && (!shift))2192{2193genUnary(TR::i2l, isForArrayAccess);2194}21952196genBinary(TR::aladd);2197}2198else2199{2200if (headerSize > 0)2201{2202loadConstant(TR::iconst, headerSize);2203genBinary(TR::iadd);2204}2205genBinary(TR::aiadd);2206}2207}22082209// Helper to calculate the index of the array element in a contiguous array2210// Stack: ..., offset for array element index2211// width is the width of each array element in bytes2212// headerSize is the number of header bytes at the beginning of the array2213void2214TR_J9ByteCodeIlGenerator::calculateIndexFromOffsetInContiguousArray(int32_t width, int32_t headerSize)2215{22162217if (comp()->target().is64Bit())2218{2219if (headerSize > 0)2220{2221loadConstant(TR::lconst, (int64_t)headerSize);22222223genBinary(TR::lsub);2224}2225}2226else2227{2228if (headerSize > 0)2229{2230loadConstant(TR::iconst, headerSize);2231genBinary(TR::isub);2232}2233}22342235int32_t shift = TR::TransformUtil::convertWidthToShift(width);2236if (shift)2237{2238loadConstant(TR::iconst, shift);2239if (comp()->target().is64Bit())2240{2241genBinary(TR::lshr);2242genUnary(TR::l2i);2243}2244else2245genBinary(TR::ishr);2246}2247}224822492250// Helper to calculate the address of the element of an array2251// RTSJ: if we should be generating arraylets, access the spine2252// then the arraylet2253void2254TR_J9ByteCodeIlGenerator::calculateArrayElementAddress(TR::DataType dataType, bool checks)2255{22562257if (comp()->getOption(TR_EnableSIMDLibrary))2258{2259if (dataType == TR::VectorInt8)2260dataType = TR::Int8;2261else if (dataType == TR::VectorInt16)2262dataType = TR::Int16;2263else if (dataType == TR::VectorInt32)2264dataType = TR::Int32;2265else if (dataType == TR::VectorInt64)2266dataType = TR::Int64;2267if (dataType == TR::VectorFloat)2268dataType = TR::Float;2269else if (dataType == TR::VectorDouble)2270dataType = TR::Double;2271}22722273int32_t width = TR::Symbol::convertTypeToSize(dataType);22742275// since each element of an reference array is a compressed pointer,2276// modify the width accordingly, so the stride is 4bytes instead of 82277//2278if (comp()->useCompressedPointers() && dataType == TR::Address)2279{2280width = TR::Compiler->om.sizeofReferenceField();2281}22822283// Stack is now ...,aryRef,index<===2284TR::Node * index = pop();2285if (checks) dup();2286dup();2287TR::Node * nodeThatWasNullChecked = pop();22882289handlePendingPushSaveSideEffects(index);2290handlePendingPushSaveSideEffects(nodeThatWasNullChecked);22912292if (checks)2293{2294genArrayBoundsCheck(index, width);2295}2296else2297{2298push(index);2299}23002301// Stack is now ...,aryRef,index<===2302if (comp()->generateArraylets())2303{2304// shift the index on the current stack to get index into array spine2305loadConstant(TR::iconst, fej9()->getArraySpineShift(width));2306genBinary(TR::ishr);23072308// now calculate address of pointer to appropriate arraylet2309int32_t arraySpineHeaderSize = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();2310calculateElementAddressInContiguousArray(TR::Compiler->om.sizeofReferenceField(), arraySpineHeaderSize);23112312// fetch the arraylet base address2313TR::Node * elementAddress = pop();2314TR::SymbolReference * elementSymRef = symRefTab()->findOrCreateArrayletShadowSymbolRef(dataType);2315TR::Node * arrayletBaseAddr = TR::Node::createWithSymRef(TR::aloadi, 1, 1, elementAddress, elementSymRef);2316if (comp()->useCompressedPointers())2317{2318TR::Node *newArrayletBaseAddr = genCompressedRefs(arrayletBaseAddr);2319if (newArrayletBaseAddr)2320arrayletBaseAddr = newArrayletBaseAddr;2321}23222323push(arrayletBaseAddr);23242325// top of stack is now arraylet base address23262327// get the original index back, mask it to get index into arraylet2328push(index);2329loadConstant(TR::iconst, fej9()->getArrayletMask(width));2330genBinary(TR::iand);23312332// figure out the address of the element we want in the arraylet2333int32_t arrayletHeaderSize = 0;2334calculateElementAddressInContiguousArray(width, arrayletHeaderSize);2335}2336else2337{2338int32_t arrayHeaderSize = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();2339calculateElementAddressInContiguousArray(width, arrayHeaderSize);2340_stack->top()->setIsInternalPointer(true);2341}23422343push(nodeThatWasNullChecked);2344}23452346//----------------------------------------------2347// gen check2348//----------------------------------------------23492350void2351TR_J9ByteCodeIlGenerator::genAsyncCheck()2352{2353// Create an asyncCheck tree and insert it at the start of the current block2354//23552356TR::Node *node = TR::Node::createWithSymRef(TR::asynccheck,0,symRefTab()->findOrCreateAsyncCheckSymbolRef(_methodSymbol));23572358if (comp()->getOption(TR_EnableOSR))2359genTreeTop(node);2360else2361_block->prepend(TR::TreeTop::create(comp(), node));2362}23632364/**2365* Pop object and class nodes from the stack, and emit a checkcast tree.2366*2367* @return The emitted checkcast tree2368*/2369void2370TR_J9ByteCodeIlGenerator::genCheckCast()2371{2372if (_methodSymbol->safeToSkipCheckCasts())2373{2374pop();2375return;2376}23772378TR::Node *node = genNodeAndPopChildren(TR::checkcast, 2, symRefTab()->findOrCreateCheckCastSymbolRef(_methodSymbol));2379genTreeTop(node);2380push(node->getFirstChild()); // The object reference2381_methodSymbol->setHasCheckCasts(true);2382}23832384/**2385* Generate IL for a checkcast bytecode instruction.2386*2387* If the class specified in the bytecode is unresolved, this leaves out the2388* ResolveCHK since it has to be conditional on a non-null object.2389* If the class specified in the bytecode is a value type, it has to be resolved2390* unconditionally, regardless of whether the value is null.2391*2392* @param cpIndex The constant pool entry of the class given in the bytecode2393*2394* @see expandUnresolvedClassTypeTests(List<TR::TreeTop>*)2395* @see expandUnresolvedClassCheckcast(TR::TreeTop*)2396*/2397void2398TR_J9ByteCodeIlGenerator::genCheckCast(int32_t cpIndex)2399{2400if (TR::Compiler->om.areValueTypesEnabled() && TR::Compiler->cls.isClassRefValueType(comp(), method()->classOfMethod(), cpIndex))2401{2402TR::Node * objNode = _stack->top();24032404loadClassObject(cpIndex);24052406TR::Node *passThruNode = TR::Node::create(TR::PassThrough, 1, objNode);2407genTreeTop(genNullCheck(passThruNode));2408}2409else2410{2411loadClassObjectForTypeTest(cpIndex, TR_DisableAOTCheckCastInlining);2412}2413genCheckCast();2414}24152416void2417TR_J9ByteCodeIlGenerator::genDivCheck()2418{2419if (!_methodSymbol->skipDivChecks())2420{2421if (!cg()->getSupportsDivCheck())2422_unimplementedOpcode = _code[_bcIndex];2423genTreeTop(TR::Node::createWithSymRef(TR::DIVCHK, 1, 1, _stack->top(), symRefTab()->findOrCreateDivCheckSymbolRef(_methodSymbol)));2424}2425}24262427// create an integer divide node like:2428// div2429// load i2430// load j2431// rem2432// ==> load i2433// ==> load j2434// so that if the remainder can be commoned then on most platforms the rem is free with the div calculation2435//2436void2437TR_J9ByteCodeIlGenerator::genIDiv()2438{2439if (cg()->getSupportsIDivAndIRemWithThreeChildren())2440{2441genBinary(TR::idiv, 3);2442TR::Node * div = _stack->top();2443div->setAndIncChild(2, TR::Node::create(TR::irem, 2, div->getFirstChild(), div->getSecondChild()));2444}2445else2446genBinary(TR::idiv);24472448genDivCheck();2449}24502451void2452TR_J9ByteCodeIlGenerator::genLDiv()2453{2454if (cg()->getSupportsLDivAndLRemWithThreeChildren())2455{2456genBinary(TR::ldiv, 3);2457TR::Node * div = _stack->top();2458div->setAndIncChild(2, TR::Node::create(TR::lrem, 2, div->getFirstChild(), div->getSecondChild()));2459}2460else2461genBinary(TR::ldiv);24622463genDivCheck();2464}24652466void2467TR_J9ByteCodeIlGenerator::genIRem()2468{2469if (cg()->getSupportsIDivAndIRemWithThreeChildren())2470{2471genBinary(TR::irem, 3);2472TR::Node * rem = _stack->top();2473rem->setAndIncChild(2, TR::Node::create(TR::idiv, 2, rem->getFirstChild(), rem->getSecondChild()));2474}2475else2476genBinary(TR::irem);24772478genDivCheck();2479}24802481void2482TR_J9ByteCodeIlGenerator::genLRem()2483{2484if (cg()->getSupportsLDivAndLRemWithThreeChildren())2485{2486genBinary(TR::lrem, 3);2487TR::Node * rem = _stack->top();2488rem->setAndIncChild(2, TR::Node::create(TR::ldiv, 2, rem->getFirstChild(), rem->getSecondChild()));2489}2490else2491genBinary(TR::lrem);24922493genDivCheck();2494}249524962497/**2498* Generate IL for an instanceof bytecode instruction.2499*2500* If the class specified in the bytecode is unresolved, this anchors the2501* instanceof node, and it leaves out the ResolveCHK since that has to be2502* conditional on a non-null object.2503*2504* @param cpIndex The constant pool entry of the class given in the bytecode2505*2506* @see expandUnresolvedClassTypeTests(List<TR::TreeTop>*)2507* @see expandUnresolvedClassInstanceof(TR::TreeTop*)2508*/2509void2510TR_J9ByteCodeIlGenerator::genInstanceof(int32_t cpIndex)2511{2512TR::SymbolReference *classSymRef = loadClassObjectForTypeTest(cpIndex, TR_DisableAOTInstanceOfInlining);2513TR::Node *node = genNodeAndPopChildren(TR::instanceof, 2, symRefTab()->findOrCreateInstanceOfSymbolRef(_methodSymbol));2514push(node);2515if (classSymRef->isUnresolved())2516{2517// Anchor to ensure sequencing for the implied (conditional) ResolveCHK.2518genTreeTop(node);2519}2520_methodSymbol->setHasInstanceOfs(true);2521}25222523TR::Node *2524TR_J9ByteCodeIlGenerator::genCompressedRefs(TR::Node * address, bool genTT, int32_t isLoad)2525{2526static char *pEnv = feGetEnv("TR_UseTranslateInTrees");25272528TR::Node *value = address;2529if (pEnv && (isLoad < 0)) // store2530value = address->getSecondChild();2531TR::Node *newAddress = TR::Node::createCompressedRefsAnchor(value);2532//traceMsg(comp(), "compressedRefs anchor %p generated\n", newAddress);25332534if (trace())2535traceMsg(comp(), "IlGenerator: Generating compressedRefs anchor [%p] for node [%p]\n", newAddress, address);25362537if (!pEnv && genTT)2538{2539genTreeTop(newAddress);2540return NULL;2541}2542else2543{2544return newAddress;2545}2546}254725482549TR::Node *2550TR_J9ByteCodeIlGenerator::genNullCheck(TR::Node * first)2551{2552// By default, NULLCHKs will be skipped on String.value fields. A more general mechanism2553// is needed for skipping NULL/BNDCHKs on certain recognized fields...2554//2555static char *c = feGetEnv("TR_disableSkipStringValueNULLCHK");25562557if (!_methodSymbol->skipNullChecks())2558{2559TR_ASSERT(first->getNumChildren() >= 1, "no grandchild to nullcheck?");2560TR::Node *grandChild = first->getChild(0);2561if (!c && grandChild->getOpCode().hasSymbolReference() &&2562grandChild->getSymbolReference() &&2563grandChild->getSymbolReference()->getSymbol() &&2564grandChild->getSymbolReference()->getSymbol()->getRecognizedField() == TR::Symbol::Java_lang_String_value)2565{2566if (trace())2567traceMsg(comp(), "Skipping NULLCHK (node %p) on String.value field : %s -> %s\n", grandChild, comp()->signature(), _methodSymbol->signature(trMemory()));2568}2569else2570{2571return TR::Node::createWithSymRef(TR::NULLCHK, 1, 1, first, symRefTab()->findOrCreateNullCheckSymbolRef(_methodSymbol));2572}2573}25742575if (first->getOpCode().isTreeTop())2576return first;25772578return TR::Node::create(TR::treetop, 1, first);2579}25802581TR::Node *2582TR_J9ByteCodeIlGenerator::genResolveCheck(TR::Node * first)2583{2584return TR::Node::createWithSymRef(TR::ResolveCHK, 1, 1, first, symRefTab()->findOrCreateResolveCheckSymbolRef(_methodSymbol));2585}25862587TR::Node *2588TR_J9ByteCodeIlGenerator::genResolveAndNullCheck(TR::Node * first)2589{2590TR_ASSERT(first->getNumChildren() >= 1, "no grandchild to nullcheck?");2591TR::Node *grandChild = first->getChild(0);2592return TR::Node::createWithSymRef(TR::ResolveAndNULLCHK, 1, 1, first, symRefTab()->findOrCreateNullCheckSymbolRef(_methodSymbol));2593}25942595//----------------------------------------------2596// genGoto2597//----------------------------------------------25982599int32_t2600TR_J9ByteCodeIlGenerator::genGoto(int32_t target)2601{26022603if( _blocksToInline) // partial inlining - only generate goto if its in the list of blocks.2604{2605bool success=false;2606ListIterator<TR_InlineBlock> blocksIt(_blocksToInline->_inlineBlocks);2607TR_InlineBlock *aBlock = NULL;2608for (aBlock = blocksIt.getCurrent() ; aBlock; aBlock = blocksIt.getNext())2609{2610if ( aBlock->_BCIndex == target)2611{2612if (_blocks[target]->getEntry()->getNode()->getByteCodeIndex()<= _block->getEntry()->getNode()->getByteCodeIndex())2613genAsyncCheck();2614genTreeTop(TR::Node::create(TR::Goto, 0, genTarget(target)));2615success=true;2616break;2617}2618}2619TR_ASSERT(success, " Walker: genGoto for a partial inline has no target in the list of blocks to be inlined.\n");2620}2621else2622{26232624if (_blocks[target]->getEntry()->getNode()->getByteCodeIndex()2625<= _block->getEntry()->getNode()->getByteCodeIndex())2626genAsyncCheck();26272628genTreeTop(TR::Node::create(TR::Goto, 0, genTarget(target)));2629}2630return findNextByteCodeToGen();2631}2632263326342635/** \brief2636* Generates IL for an conditional branch bytecode that takes one operand.2637* Also generates an asynccheck if the bytecode branches backwards.2638*2639* \param nodeop2640* The IL opcode to use.2641*2642* \return2643* The index of the next bytecode to generate.2644*/2645int32_t2646TR_J9ByteCodeIlGenerator::genIfOneOperand(TR::ILOpCodes nodeop)2647{2648int32_t branchBC = _bcIndex + next2BytesSigned();26492650if (branchBC <= _bcIndex)2651genAsyncCheck();26522653TR_J9ByteCode currentByteCode = current();2654switch (currentByteCode)2655{2656case J9BCifeq:2657case J9BCifne:2658case J9BCiflt:2659case J9BCifge:2660case J9BCifgt:2661case J9BCifle:2662loadConstant(TR::iconst, 0);2663break;2664case J9BCifnull:2665if (comp()->target().is64Bit())2666loadConstant(TR::aconst, (int64_t)0);2667else2668loadConstant(TR::aconst, (int32_t)0);2669break;2670case J9BCifnonnull:2671if (comp()->target().is64Bit())2672loadConstant(TR::aconst, (int64_t)0);2673else2674loadConstant(TR::aconst, (int32_t)0);2675break;2676default:2677TR_ASSERT(comp(), "Unexpected bytecode at bc index %d\n", _bcIndex);2678}26792680return genIfImpl(nodeop);2681}26822683/** \brief2684* Generates IL for an conditional branch bytecode that takes two operands.2685* Also generates an asynccheck if the bytecode branches backwards.2686*2687* \param nodeop2688* The IL opcode to use.2689*2690* \return2691* The index of the next bytecode to generate.2692*/2693int32_t2694TR_J9ByteCodeIlGenerator::genIfTwoOperand(TR::ILOpCodes nodeop)2695{2696int32_t branchBC = _bcIndex + next2BytesSigned();26972698if (branchBC <= _bcIndex)2699genAsyncCheck();27002701return genIfImpl(nodeop);2702}27032704/** \brief2705* Generates IL for a conditional branch bytecode that compares two2706* address-typed operands as for bytecode instructions if_acmp{eq,ne}.2707* Also generates an asynccheck if the bytecode branches backwards.2708*2709* If value types are not enabled, then a regulare acmp operation is2710* generated instead.2711*2712* \param nodeop2713* The IL opcode that would be used for non-value references. This opcode2714* must be either ifacmpeq or ifacmpne.2715*2716* \return2717* The index of the next bytecode to generate.2718*/2719int32_t2720TR_J9ByteCodeIlGenerator::genIfAcmpEqNe(TR::ILOpCodes ifacmpOp)2721{2722if (!TR::Compiler->om.areValueTypesEnabled())2723return genIfTwoOperand(ifacmpOp);27242725int32_t branchBC = _bcIndex + next2BytesSigned();27262727if (branchBC <= _bcIndex)2728genAsyncCheck();27292730TR::Node *rhs = pop();2731TR::Node *lhs = pop();27322733TR::SymbolReference *comparisonNonHelper =2734comp()->getSymRefTab()->findOrCreateObjectInequalityComparisonSymbolRef();27352736TR::Node *substitutabilityTest =2737TR::Node::createWithSymRef(TR::icall, 2, 2, lhs, rhs, comparisonNonHelper);27382739substitutabilityTest->getByteCodeInfo().setDoNotProfile(true);2740TR::TreeTop* callTree = genTreeTop(substitutabilityTest);27412742const char *counterName = TR::DebugCounter::debugCounterName(comp(), "vt-helper/generated/acmp/(%s)/bc=%d",2743comp()->signature(), currentByteCodeIndex());2744TR::DebugCounter::prependDebugCounter(comp(), counterName, callTree);27452746push(substitutabilityTest);2747push(TR::Node::iconst(0));2748return genIfImpl(ifacmpOp == TR::ifacmpeq ? TR::ificmpeq : TR::ificmpne);2749}27502751//----------------------------------------------2752// genIfImpl2753//----------------------------------------------27542755// The "if" family of bytecodes are composed of two operations: a2756// compare and a conditional branch. Like bytecode, the TR IL combines2757// them into one operation. The combined operation, obviously, has to2758// be the last operation in the basic block.2759//2760// This complicates our scheme for handling PPS slots that are live2761// across blocks. The saveStack method will generate stores of any PPS2762// slots live on exit. However, these stores must be generated before2763// the combined compare/conditional branch operation. Thus, any loads2764// from the PPS save region amongst the inputs of the compare might be2765// killed by stores to be generated by saveStack. The method2766// handlePendingPushSaveSideEffects is called to promote any such loads2767// to treetops preceding the saveStack generated stores.2768//2769// This API does not generate asynccheck, it's the caller's responsibility2770// to ensure one is generated for a backward branch.2771//2772int32_t2773TR_J9ByteCodeIlGenerator::genIfImpl(TR::ILOpCodes nodeop)2774{2775int32_t branchBC = _bcIndex + next2BytesSigned();2776int32_t fallThruBC = _bcIndex + 3;27772778TR::Node * second = pop();2779TR::Node * first = pop();27802781static char *disableIfFolding = feGetEnv("TR_DisableIfFolding");2782bool trace = comp()->getOption(TR_TraceILGen);27832784TR::DataType type = first->getDataType();2785if (!disableIfFolding &&2786branchBC > _bcIndex &&2787first->getOpCode().isLoadConst() &&2788second->getOpCode().isLoadConst() &&2789type != TR::Address &&2790type != TR::Float &&2791type != TR::Double)2792{2793int64_t v1 = first->getConstValue();2794int64_t v2 = second->getConstValue();2795bool branchTaken;2796TR_ComparisonTypes compareType = TR::ILOpCode::getCompareType(nodeop);2797bool isUnsignedCompare = TR::ILOpCode(nodeop).isUnsignedCompare();2798switch (compareType)2799{2800case TR_cmpEQ:2801branchTaken = v1 == v2;2802break;2803case TR_cmpNE:2804branchTaken = v1 != v2;2805break;2806case TR_cmpLT:2807branchTaken = isUnsignedCompare ? (uint64_t)v1 < (uint64_t)v2 : v1 < v2;2808break;2809case TR_cmpLE:2810branchTaken = isUnsignedCompare ? (uint64_t)v1 <= (uint64_t)v2 : v1 <= v2;2811break;2812case TR_cmpGT:2813branchTaken = isUnsignedCompare ? (uint64_t)v1 > (uint64_t)v2 : v1 > v2;2814break;2815case TR_cmpGE:2816branchTaken = isUnsignedCompare ? (uint64_t)v1 >= (uint64_t)v2 : v1 >= v2;2817break;2818}28192820if (_blocksToInline)2821{2822if (trace)2823traceMsg(comp(), "Not folding the if because of partial inlining\n");2824}2825else2826{2827if (trace)2828traceMsg(comp(), "%s\n", branchTaken ? "taking the branch" : "fall through");28292830if (branchTaken)2831{2832// Folding the if is equivalent to turning it into a goto. We can't just return2833// branchBC because there can be arbitrary bytecodes between the `if` and branchBC.2834// To get a correct CFG, a goto is required.2835//2836return genGoto(branchBC);2837}2838else2839{2840// In this case, folding the if is equivalent to removing the if bytecode. The fall2841// through bytecodes can live in the same block as there is no branch out after the2842// folding.2843//2844return fallThruBC;2845}2846}2847}28482849_methodSymbol->setHasBranches(true);2850handlePendingPushSaveSideEffects(first);2851handlePendingPushSaveSideEffects(second);28522853if( _blocksToInline)2854{2855bool genFallThru=false, genBranchBC=false;2856ListIterator<TR_InlineBlock> blocksIt(_blocksToInline->_inlineBlocks);2857TR_InlineBlock *aBlock = NULL;2858for (aBlock = blocksIt.getCurrent() ; aBlock; aBlock = blocksIt.getNext())2859{2860// printf("\tBlock bcIndex = %d owningMethod = %p depth = %d\n",aBlock->_BCIndex,aBlock->_owningMethod,aBlock->_depth);2861if(branchBC == aBlock->_BCIndex)2862genBranchBC=true;2863if(fallThruBC == aBlock->_BCIndex)2864genFallThru=true;2865}2866// printf("genIf: genBranchBC = %d genFallThru = %d\n",genBranchBC,genFallThru);2867// fflush(stdout);28682869TR::TreeTop * branchDestination = NULL;28702871if(genFallThru && genBranchBC)2872{2873genTarget(fallThruBC);2874// printf("Walker: calling genTarget on branchBC\n");2875TR::TreeTop * branchDestination = genTarget(branchBC);2876if (swapChildren(nodeop, first))2877{2878TR::TreeTop *tt = genTreeTop(TR::Node::createif(TR::ILOpCode(nodeop).getOpCodeForSwapChildren(), second, first, branchDestination));2879tt->getNode()->setSwappedChildren(true);2880}2881else2882genTreeTop(TR::Node::createif(nodeop, first, second, branchDestination));28832884return findNextByteCodeToGen();2885}2886else2887{2888if(genFallThru)2889{2890genTarget(fallThruBC);28912892//need to create a branch destination restart2893// printf("Walker: genIf : fallThru : getCallNodeTreeTop = %p, symreftab = %p\n",_blocksToInline->getCallNodeTreeTop(),symRefTab());2894// fflush(stdout);2895branchDestination = _blocksToInline->hasGeneratedRestartTree() ? _blocksToInline->getGeneratedRestartTree() :2896_blocksToInline->setGeneratedRestartTree(genPartialInliningCallBack(branchBC,_blocksToInline->getCallNodeTreeTop())); //not adding it to the queue2897if(branchBC > _blocksToInline->getHighestBCIndex())2898_blocksToInline->setHighestBCIndex(branchBC);2899else if(branchBC < _blocksToInline->getLowestBCIndex())2900_blocksToInline->setLowestBCIndex(branchBC);2901//printf("Walker: genIf : fallThru : branchDestination = %p\n",branchDestination);2902// fflush(stdout);2903//_blocksToInline->getCallNodeTreeTop();2904}29052906if(genBranchBC)2907{2908//printf("Walker: genIf : BranchBC : hasGeneratedRestartTree = %d getGeneratedRestartTree = %p getEnclosingBlock = %p\n",_blocksToInline->hasGeneratedRestartTree(),_blocksToInline->getGeneratedRestartTree(), _blocksToInline->getGeneratedRestartTree() ? _blocksToInline->getGeneratedRestartTree()->getEnclosingBlock() : 0);2909// fflush(stdout);2910_blocksToInline->hasGeneratedRestartTree() ? genGotoPartialInliningCallBack(fallThruBC,_blocksToInline->getGeneratedRestartTree()) :2911_blocksToInline->setGeneratedRestartTree(genPartialInliningCallBack(fallThruBC,_blocksToInline->getCallNodeTreeTop()));2912if(fallThruBC > _blocksToInline->getHighestBCIndex())2913_blocksToInline->setHighestBCIndex(fallThruBC);2914else if(fallThruBC < _blocksToInline->getLowestBCIndex())2915_blocksToInline->setLowestBCIndex(fallThruBC);2916branchDestination = genTarget(branchBC);2917//printf("Walker: genIf : BranchBC : branchDestination = %p\n",branchDestination);2918// fflush(stdout);2919//genTreeTop(TR::Node::create(TR::Goto, 0, genTarget(target)));2920}2921//generating the if statement regardless methinks2922TR_ASSERT(branchDestination, "Walker: No branchDestination in partial inlining\n");2923if (swapChildren(nodeop, first))2924{2925TR::TreeTop *tt = genTreeTop(TR::Node::createif(TR::ILOpCode(nodeop).getOpCodeForSwapChildren(), second, first, branchDestination));2926tt->getNode()->setSwappedChildren(true);2927}2928else2929genTreeTop(TR::Node::createif(nodeop, first, second, branchDestination));29302931return findNextByteCodeToGen();2932}2933}2934else2935{2936genTarget(fallThruBC);2937// printf("Walker: calling genTarget on branchBC\n");2938TR::TreeTop * branchDestination = genTarget(branchBC);2939if (swapChildren(nodeop, first))2940{2941TR::TreeTop *tt = genTreeTop(TR::Node::createif(TR::ILOpCode(nodeop).getOpCodeForSwapChildren(), second, first, branchDestination));2942tt->getNode()->setSwappedChildren(true);2943}2944else2945genTreeTop(TR::Node::createif(nodeop, first, second, branchDestination));29462947return findNextByteCodeToGen();2948}2949}29502951//----------------------------------------------2952// genInc2953//----------------------------------------------29542955void2956TR_J9ByteCodeIlGenerator::genInc()2957{2958int32_t index = nextByte();2959loadAuto(TR::Int32, index);2960loadConstant(TR::iconst, nextByteSigned(2));2961genBinary(TR::iadd);2962storeAuto(TR::Int32, index);2963}29642965void2966TR_J9ByteCodeIlGenerator::genIncLong()2967{2968int32_t index = next2Bytes();2969loadAuto(TR::Int32, index);2970loadConstant(TR::iconst, next2BytesSigned(3));2971genBinary(TR::iadd);2972storeAuto(TR::Int32, index);2973}29742975//----------------------------------------------2976// genInvoke2977//----------------------------------------------29782979void2980TR_J9ByteCodeIlGenerator::genInvokeStatic(int32_t cpIndex)2981{2982TR::SymbolReference *methodSymRef = symRefTab()->findOrCreateStaticMethodSymbol(_methodSymbol, cpIndex);29832984if (comp()->getOption(TR_TraceILGen))2985traceMsg(comp(), " genInvokeStatic(%d) // %s\n", cpIndex, comp()->getDebug()->getName(methodSymRef));29862987_staticMethodInvokeEncountered = true;29882989if (runMacro(methodSymRef))2990{2991if (comp()->compileRelocatableCode())2992{2993if (comp()->getOption(TR_TraceILGen))2994traceMsg(comp(), " ILGen macro %s not supported in AOT. Aborting compile.\n", comp()->getDebug()->getName(methodSymRef));2995comp()->failCompilation<J9::AOTHasInvokeHandle>("An ILGen macro not supported in AOT. Aborting compile.");2996}29972998if (comp()->getOption(TR_FullSpeedDebug) && !isPeekingMethod())2999{3000if (comp()->getOption(TR_TraceILGen))3001traceMsg(comp(), " ILGen macro %s not supported in FSD. Failing ilgen\n", comp()->getDebug()->getName(methodSymRef));3002comp()->failCompilation<J9::FSDHasInvokeHandle>("An ILGen macro not supported in FSD. Failing ilgen.");3003}30043005if (comp()->getOption(TR_TraceILGen))3006traceMsg(comp(), " Finished macro %s\n", comp()->getDebug()->getName(methodSymRef));3007return;3008}30093010TR::MethodSymbol * symbol = methodSymRef->getSymbol()->castToMethodSymbol();3011// Note that genInvokeDirect can return nodes that are not calls (for3012// recognized methods), so some caution is needed in the handling of callNode.3013TR::Node *callNode = genInvokeDirect(methodSymRef);3014if (callNode && _methodSymbol->safeToSkipChecksOnArrayCopies())3015{3016bool isCallToArrayCopy = true;3017// Defend against the case where there is no symbol reference3018if (callNode->getOpCode().hasSymbolReference() && !callNode->getSymbolReference()->isUnresolved())3019{3020TR::RecognizedMethod recognizedMethod = callNode->getSymbol()->castToResolvedMethodSymbol()->getRecognizedMethod();30213022if (recognizedMethod != TR::java_lang_System_arraycopy &&3023recognizedMethod != TR::java_lang_String_compressedArrayCopy_BIBII &&3024recognizedMethod != TR::java_lang_String_compressedArrayCopy_BICII &&3025recognizedMethod != TR::java_lang_String_compressedArrayCopy_CIBII &&3026recognizedMethod != TR::java_lang_String_compressedArrayCopy_CICII &&3027recognizedMethod != TR::java_lang_String_decompressedArrayCopy_BIBII &&3028recognizedMethod != TR::java_lang_String_decompressedArrayCopy_BICII &&3029recognizedMethod != TR::java_lang_String_decompressedArrayCopy_CIBII &&3030recognizedMethod != TR::java_lang_String_decompressedArrayCopy_CICII)3031{3032isCallToArrayCopy = false;3033}3034}3035else3036isCallToArrayCopy = false;30373038if (isCallToArrayCopy)3039callNode->setNodeIsRecognizedArrayCopyCall(true);3040}3041}30423043void3044TR_J9ByteCodeIlGenerator::genInvokeSpecial(int32_t cpIndex)3045{3046TR::SymbolReference *methodSymRef = symRefTab()->findOrCreateSpecialMethodSymbol(_methodSymbol, cpIndex);30473048genInvokeDirect(methodSymRef);30493050// In bytecode within an interface, invokespecial instructions calling3051// anything other than <init> need to have a run-time type test to ensure3052// that the receiver is an instance of the interface. Outside of interfaces3053// this is checked during verification, but verification doesn't check3054// interface types.3055//3056// The following collects the bytecode index of each invokespecial3057// instruction that requires such a type test. The tests are inserted later3058// by expandInvokeSpecialInterface().30593060const bool trace = comp()->getOption(TR_TraceILGen);3061if (skipInvokeSpecialInterfaceTypeChecks())3062{3063if (trace)3064traceMsg(comp(), "invokespecial type tests disabled by env var\n");3065return;3066}30673068// Initialize _invokeSpecialInterface if necessary.3069if (!_invokeSpecialSeen)3070{3071_invokeSpecialSeen = true;30723073// For this purpose, an anonymous class whose host class is an interface3074// is expected to behave as though its code is contained within that3075// interface. For non-anonymous classes, hostClass is circular.3076TR_OpaqueClassBlock * const defClass =3077fej9()->getHostClass(_method->containingClass());3078if (TR::Compiler->cls.isInterfaceClass(comp(), defClass))3079_invokeSpecialInterface = defClass;30803081if (trace)3082{3083int32_t len = 6;3084const char * name = "(none)";3085if (_invokeSpecialInterface != NULL)3086name = fej9()->getClassNameChars(_invokeSpecialInterface, len);3087traceMsg(comp(),3088"within interface %p %.*s for the purpose of invokespecial\n",3089_invokeSpecialInterface,3090len, name);3091}3092}30933094if (_invokeSpecialInterface == NULL)3095{3096if (trace)3097traceMsg(comp(), "no invokespecial type tests in this method\n");3098return;3099}31003101TR::Method *callee = methodSymRef->getSymbol()->castToMethodSymbol()->getMethod();3102if (callee->isConstructor())3103{3104if (trace)3105traceMsg(comp(), "no invokespecial type test for constructor\n");3106return;3107}31083109if (callee->isFinalInObject())3110{3111if (trace)3112traceMsg(comp(), "invokespecial of final Object method is really invokevirtual\n");3113return;3114}31153116const int32_t bcIndex = currentByteCodeIndex();3117if (comp()->compileRelocatableCode())3118{3119if (isOutermostMethod())3120{3121TR::DebugCounter::incStaticDebugCounter(comp(),3122TR::DebugCounter::debugCounterName(comp(),3123"ilgen.abort/aot-invokespecial-interface/root/(%s)/bc=%d",3124comp()->signature(),3125bcIndex));3126}3127else3128{3129TR::DebugCounter::incStaticDebugCounter(comp(),3130TR::DebugCounter::debugCounterName(comp(),3131"ilgen.abort/aot-invokespecial-interface/inline/(%s)/bc=%d/root=(%s)",3132_method->signature(comp()->trMemory()),3133bcIndex,3134comp()->signature()));3135}31363137comp()->failCompilation<J9::AOTHasInvokeSpecialInInterface>(3138"COMPILATION_AOT_HAS_INVOKESPECIAL_IN_INTERFACE");3139}31403141// Make note of this invokespecial; it needs a run-time type test against3142// _invokeSpecialInterface.3143if (_invokeSpecialInterfaceCalls == NULL) // lazily allocated3144{3145_invokeSpecialInterfaceCalls =3146new (trHeapMemory()) TR_BitVector(_maxByteCodeIndex + 1, trMemory());3147}31483149_invokeSpecialInterfaceCalls->set(bcIndex);3150if (trace)3151traceMsg(comp(), "request invokespecial type test at bc index %d\n", bcIndex);3152}31533154void3155TR_J9ByteCodeIlGenerator::genInvokeVirtual(int32_t cpIndex)3156{3157auto owningMethod = (TR_ResolvedJ9Method*)_methodSymbol->getResolvedMethod();3158bool unresolvedInCP;3159TR_ResolvedMethod *method =3160owningMethod->getResolvedPossiblyPrivateVirtualMethod(3161comp(),3162cpIndex,3163/* ignoreRtResolve = */ false,3164&unresolvedInCP);31653166TR::SymbolReference * symRef = NULL;3167if (method != NULL && method->isPrivate())3168{3169_methodSymbol->setMayHaveInlineableCall(true);3170symRef = symRefTab()->findOrCreateMethodSymbol(3171_methodSymbol->getResolvedMethodIndex(),3172cpIndex,3173method,3174TR::MethodSymbol::Special,3175/* isUnresolvedInCP = */ false);3176}3177else3178{3179symRef = symRefTab()->findOrCreateVirtualMethodSymbol(_methodSymbol, cpIndex);31803181// Update method in case getResolvedPossiblyPrivateVirtualMethod()3182// returned null originally, but then findOrCreateVirtualMethodSymbol()3183// later found the method.3184//3185// Without doing this, we can fail to set isDirectCall for recognized3186// final methods (e.g. Unsafe and JITHelpers methods) where the compiler3187// assumes calls are direct.3188//3189if (!symRef->isUnresolved())3190method = symRef->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod();3191}31923193bool isDirectCall = false;3194if (method != NULL)3195{3196isDirectCall =3197symRef->getSymbol()->isFinal() ||3198method->isPrivate() ||3199(debug("omitVirtualGuard") && !method->virtualMethodIsOverridden());3200}32013202if (isDirectCall)3203{3204genInvokeDirect(symRef);3205}3206else3207{3208genInvokeWithVFTChild(symRef);3209_methodSymbol->setMayHaveIndirectCalls(true);3210}3211}32123213void3214TR_J9ByteCodeIlGenerator::genInvokeInterface(int32_t cpIndex)3215{3216auto owningMethod = (TR_ResolvedJ9Method*)_methodSymbol->getResolvedMethod();3217TR_ResolvedMethod *improperMethod =3218owningMethod->getResolvedImproperInterfaceMethod(comp(), cpIndex);3219if (improperMethod == NULL)3220{3221TR::SymbolReference *symRef = symRefTab()->findOrCreateInterfaceMethodSymbol(_methodSymbol, cpIndex);3222genInvokeWithVFTChild(symRef);3223_methodSymbol->setMayHaveIndirectCalls(true);3224}3225else3226{3227_methodSymbol->setMayHaveInlineableCall(true);3228TR::TreeTop *prevLastTree = _block->getExit()->getPrevTreeTop();3229TR::Node *callNode = NULL;3230TR::Node *receiver = topn(improperMethod->numberOfExplicitParameters());3231if (improperMethod->isPrivate() || improperMethod->convertToMethod()->isFinalInObject())3232{3233TR::SymbolReference *symRef = symRefTab()->findOrCreateMethodSymbol(3234_methodSymbol->getResolvedMethodIndex(),3235cpIndex,3236improperMethod,3237TR::MethodSymbol::Special,3238/* isUnresolvedInCP = */ false);32393240callNode = genInvokeDirect(symRef);3241}3242else3243{3244TR::SymbolReference *symRef = symRefTab()->findOrCreateMethodSymbol(3245_methodSymbol->getResolvedMethodIndex(),3246cpIndex,3247improperMethod,3248TR::MethodSymbol::Virtual,3249/* isUnresolvedInCP = */ false);32503251callNode = genInvokeWithVFTChild(symRef);3252_methodSymbol->setMayHaveIndirectCalls(true);3253}32543255// Generate the dynamic type test against the interface type, throwing3256// IncompatibleClassChangeError in case it fails3257TR::TreeTop *bbExit = _block->getExit();3258TR::TreeTop *callTree = prevLastTree->getNextTreeTop();3259while (callTree != bbExit && callTree->getNode()->getChild(0) != callNode)3260callTree = callTree->getNextTreeTop();32613262TR_ASSERT_FATAL(callTree != bbExit, "invokeinterface call tree not found\n");32633264TR::TransformUtil::separateNullCheck(comp(), callTree, comp()->getOption(TR_TraceILGen));32653266uint32_t interfaceCPIndex = owningMethod->classCPIndexOfMethod(cpIndex);3267push(receiver);3268genInstanceof(interfaceCPIndex);3269TR::Node *instanceof = pop();32703271TR::SymbolReference *icce =3272symRefTab()->findOrCreateIncompatibleClassChangeErrorSymbolRef(_methodSymbol);32733274TR::Node *check =3275TR::Node::createWithSymRef(TR::ZEROCHK, 1, 1, instanceof, icce);32763277callTree->insertBefore(TR::TreeTop::create(comp(), check));3278}3279}32803281static char *suffixedName(char *baseName, char typeSuffix, char *buf, int32_t bufSize, TR::Compilation *comp)3282{3283char *methodName = buf;3284int32_t methodNameLength = strlen(baseName) + 2;3285if (methodNameLength >= bufSize)3286methodName = (char*)comp->trMemory()->allocateStackMemory(methodNameLength+1, TR_MemoryBase::IlGenerator);3287sprintf(methodName, "%s%c", baseName, typeSuffix);3288return methodName;3289}32903291void3292TR_J9ByteCodeIlGenerator::genInvokeDynamic(int32_t callSiteIndex)3293{3294if (comp()->compileRelocatableCode())3295{3296comp()->failCompilation<J9::AOTHasInvokeHandle>("COMPILATION_AOT_HAS_INVOKEHANDLE 0");3297}32983299if (comp()->getOption(TR_FullSpeedDebug) && !isPeekingMethod())3300comp()->failCompilation<J9::FSDHasInvokeHandle>("FSD_HAS_INVOKEHANDLE 0");3301#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)33023303// Call generated when call site table entry is resolved:3304// -----------------------------------------------------3305// call <target method obtained from memberName object>3306// arg03307// arg13308// ...3309// aloadi <appendix object>3310// ------------------------------------------------------3311// Call generated when call site table entry is unresolved:3312// ------------------------------------------------------3313// ResolveCHK3314// aload <CallSiteTableEntry @<callSiteIndex>>3315// treetop3316// aloadi <appendix object> // array-shadow from CallSiteTableEntry3317// ...3318// treetop3319// aloadi <memberName object> // array-shadow from CallSiteTableEntry3320// ...3321// treetop3322// call java/lang/invoke/MethodHandle.linkToStatic(arg0arg1...Ljava/lang/Object;Ljava/lang/Object;)<return type>3323// arg03324// arg13325// ...3326// aloadi <appendix object>3327// aloadi <memberName object>3328// ------------------------------------------------------3329bool isUnresolved;3330TR::SymbolReference * targetMethodSymRef = symRefTab()->findOrCreateDynamicMethodSymbol(_methodSymbol, callSiteIndex, &isUnresolved);3331if (isUnresolved)3332targetMethodSymRef->getSymbol()->setDummyResolvedMethod(); // linkToStatic is a dummy TR_ResolvedMethod3333TR::SymbolReference *callSiteTableEntrySymRef = symRefTab()->findOrCreateCallSiteTableEntrySymbol(_methodSymbol, callSiteIndex);3334TR_ResolvedJ9Method* owningMethod = static_cast<TR_ResolvedJ9Method *>(_methodSymbol->getResolvedMethod());3335uintptr_t * invokeCacheArray = (uintptr_t *) owningMethod->callSiteTableEntryAddress(callSiteIndex);3336loadInvokeCacheArrayElements(callSiteTableEntrySymRef, invokeCacheArray, isUnresolved);33373338if (comp()->getOption(TR_TraceILGen))3339printStack(comp(), _stack, "(Stack after load from callsite table)");33403341TR::Node* callNode = genInvokeDirect(targetMethodSymRef);33423343#else33443345TR::SymbolReference *symRef = symRefTab()->findOrCreateDynamicMethodSymbol(_methodSymbol, callSiteIndex);33463347// Compute the receiver handle3348//3349loadFromCallSiteTable(callSiteIndex);3350TR::Node *receiver = pop();33513352if (comp()->getOption(TR_TraceILGen))3353printStack(comp(), _stack, "(Stack after load from callsite table)");33543355// If the receiver handle is resolved, we can use a more specific symref3356//3357TR_ResolvedMethod * owningMethod = _methodSymbol->getResolvedMethod();3358if (!owningMethod->isUnresolvedCallSiteTableEntry(callSiteIndex))3359{3360TR_ResolvedMethod *specimen = fej9()->createMethodHandleArchetypeSpecimen(trMemory(), (uintptr_t*)owningMethod->callSiteTableEntryAddress(callSiteIndex), owningMethod);3361if (specimen)3362symRef = symRefTab()->findOrCreateMethodSymbol(_methodSymbol->getResolvedMethodIndex(), -1, specimen, TR::MethodSymbol::ComputedVirtual);3363}33643365// Emit the call3366//3367TR::Node* callNode = genInvokeHandle(symRef, receiver);33683369_invokeDynamicCalls->set(_bcIndex);33703371#endif // J9VM_OPT_OPENJDK_METHODHANDLE3372}33733374TR::Node *3375TR_J9ByteCodeIlGenerator::genInvokeHandle(int32_t cpIndex)3376{3377if (comp()->compileRelocatableCode())3378{3379comp()->failCompilation<J9::AOTHasInvokeHandle>("COMPILATION_AOT_HAS_INVOKEHANDLE 1");3380}33813382if (comp()->getOption(TR_FullSpeedDebug) && !isPeekingMethod())3383comp()->failCompilation<J9::FSDHasInvokeHandle>("FSD_HAS_INVOKEHANDLE 1");3384#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)3385// Call generated when methodType table entry is resolved:3386// -----------------------------------------------------3387// call <target method obtained from memberName object>3388// aload <Ljava/lang/invoke/MethodHandle;>3389// arg03390// arg13391// ...3392// aloadi <appendix object>3393// ------------------------------------------------------3394// Call generated when methodType table entry is unresolved:3395// ------------------------------------------------------3396// ResolveCHK3397// aload <MethodTypeTableEntry @<cpIndex>>3398// treetop3399// aloadi <appendix object> // array-shadow from MethodTypeTableEntry3400// ...3401// treetop3402// aloadi <memberName object> // array-shadow from MethodTypeTableEntry3403// ...3404// treetop3405// call java/lang/invoke/MethodHandle.linkToStatic(Ljava/lang/Object;arg0arg1...Ljava/lang/Object;Ljava/lang/Object;)<return type>3406// aload <Ljava/lang/invoke/MethodHandle;>3407// arg03408// arg13409// ...3410// aloadi <appendix object>3411// aloadi <memberName object>3412// ------------------------------------------------------3413bool isUnresolved;3414TR::SymbolReference * targetMethodSymRef = symRefTab()->findOrCreateHandleMethodSymbol(_methodSymbol, cpIndex, &isUnresolved);3415if (isUnresolved)3416targetMethodSymRef->getSymbol()->setDummyResolvedMethod(); // linkToStatic is a dummy TR_ResolvedMethod3417TR::SymbolReference *methodTypeTableEntrySymRef = symRefTab()->findOrCreateMethodTypeTableEntrySymbol(_methodSymbol, cpIndex);3418TR_ResolvedJ9Method* owningMethod = static_cast<TR_ResolvedJ9Method *>(_methodSymbol->getResolvedMethod());3419uintptr_t * invokeCacheArray = (uintptr_t *) owningMethod->methodTypeTableEntryAddress(cpIndex);3420loadInvokeCacheArrayElements(methodTypeTableEntrySymRef, invokeCacheArray, isUnresolved);34213422if (comp()->getOption(TR_TraceILGen))3423printStack(comp(), _stack, "(Stack after load from method type table)");34243425TR::Node* callNode = genInvokeDirect(targetMethodSymRef);34263427#else34283429TR::SymbolReference * invokeExactSymRef = symRefTab()->findOrCreateHandleMethodSymbol(_methodSymbol, cpIndex);34303431// Emit the call3432//3433TR::Node* callNode = genInvokeHandle(invokeExactSymRef);34343435_invokeHandleCalls->set(_bcIndex);3436#endif // J9VM_OPT_OPENJDK_METHODHANDLE34373438return callNode;3439}34403441TR::Node *3442TR_J9ByteCodeIlGenerator::genInvokeHandle(TR::SymbolReference *invokeExactSymRef, TR::Node *invokedynamicReceiver)3443{3444if (comp()->getOption(TR_TraceILGen))3445printStack(comp(), _stack, "(Stack before genInvokeHandle)");34463447TR::Node* tmpTargetAddress = TR::Node::lconst(0);3448TR::Node *callNode = genInvoke(invokeExactSymRef, tmpTargetAddress, invokedynamicReceiver);3449_methodSymbol->setMayHaveIndirectCalls(true);3450_methodSymbol->setHasMethodHandleInvokes(true);34513452if (!isPeekingMethod())3453{3454if (!comp()->getHasMethodHandleInvoke())3455{3456comp()->setHasMethodHandleInvoke(); // We only want to print this message once per compilation3457if (comp()->getOptions()->getVerboseOption(TR_VerboseMethodHandles))3458TR_VerboseLog::writeLineLocked(TR_Vlog_MH, "Jitted method contains MethodHandle invoke: %s", comp()->signature());3459}3460if (comp()->getOptions()->getVerboseOption(TR_VerboseMethodHandleDetails))3461{3462TR::Method *callee = callNode->getSymbol()->castToMethodSymbol()->getMethod();3463TR_VerboseLog::writeLineLocked(TR_Vlog_MHD, "Call to invokeExact%.*s from %s", callee->signatureLength(), callee->signatureChars(), comp()->signature());3464}3465}34663467_methodHandleInvokeCalls->set(_bcIndex);3468return callNode;3469}34703471#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)3472void3473TR_J9ByteCodeIlGenerator::loadInvokeCacheArrayElements(TR::SymbolReference *tableEntrySymRef, uintptr_t * invokeCacheArray, bool isUnresolved)3474{3475loadSymbol(TR::aload, tableEntrySymRef);3476loadConstant(TR::iconst, JSR292_invokeCacheArrayAppendixIndex);3477loadArrayElement(TR::Address, comp()->il.opCodeForIndirectArrayLoad(TR::Address), false, false);3478if (isUnresolved)3479{3480// When the callSite table entry (for invokedynamic) or methodType table entry (for invokehandle)3481// is unresolved, instead of calling the target method, we construct a call to VM internal native3482// method "linkToStatic", which expects the last arg to be the memberName object which it uses to3483// obtain the actual target method and construct the call frame for it3484loadSymbol(TR::aload, tableEntrySymRef);3485loadConstant(TR::iconst, JSR292_invokeCacheArrayMemberNameIndex);3486loadArrayElement(TR::Address, comp()->il.opCodeForIndirectArrayLoad(TR::Address), false, false);3487}3488else3489{3490// When the callSite table entry (for invokedynamic) or methodType table entry (for invokehandle)3491// is resolved, we can improve the appendix object symRef with known object index as we can get3492// the object reference of the appendix object from the invokeCacheArray entry3493TR_ResolvedJ9Method* owningMethod = static_cast<TR_ResolvedJ9Method *>(_methodSymbol->getResolvedMethod());3494TR::Node * appendixNode = _stack->top();3495TR::SymbolReference * appendixSymRef =3496fej9()->refineInvokeCacheElementSymRefWithKnownObjectIndex(3497comp(),3498appendixNode->getSymbolReference(),3499invokeCacheArray3500);3501appendixNode->setSymbolReference(appendixSymRef);3502}3503}35043505#endif35063507TR::Node *3508TR_J9ByteCodeIlGenerator::genILGenMacroInvokeExact(TR::SymbolReference *invokeExactSymRef)3509{3510TR_ASSERT(!comp()->compileRelocatableCode(), "Does not support ILGenMacro under AOT bci %d", _bcIndex);3511TR_ASSERT(!comp()->getOption(TR_FullSpeedDebug) || isPeekingMethod(), "Does not support ILGenMacro under FSD bci %d", _bcIndex);3512TR::Node* callNode = genInvokeHandle(invokeExactSymRef);35133514_ilGenMacroInvokeExactCalls->set(_bcIndex);35153516return callNode;3517}35183519TR::Node*3520TR_J9ByteCodeIlGenerator::genHandleTypeCheck(TR::Node* handle, TR::Node* expectedType)3521{3522uint32_t typeOffset = fej9()->getInstanceFieldOffsetIncludingHeader("Ljava/lang/invoke/MethodHandle;", "type", "Ljava/lang/invoke/MethodType;", method());3523TR::SymbolReference *typeSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(_methodSymbol,3524TR::Symbol::Java_lang_invoke_MethodHandle_type,3525TR::Address,3526typeOffset,3527false,3528false,3529true,3530"java/lang/invoke/MethodHandle.type Ljava/lang/invoke/MethodType;");35313532TR::Node *handleType = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectLoad(TR::Address), 1, 1, handle, typeSymRef);35333534if (comp()->getOption(TR_TraceILGen))3535{3536traceMsg(comp(), "Inserted indirect load of MethodHandle.type n%dn %p\n", handleType->getGlobalIndex(), handleType);3537}35383539// Generate zerochk3540TR::Node* zerochkNode = TR::Node::createWithSymRef(TR::ZEROCHK, 1, 1,3541TR::Node::create(TR::acmpeq, 2, expectedType, handleType),3542symRefTab()->findOrCreateMethodTypeCheckSymbolRef(_methodSymbol));3543return zerochkNode;3544}35453546TR::Node *3547TR_J9ByteCodeIlGenerator::genInvokeHandleGeneric(int32_t cpIndex)3548{3549if (comp()->compileRelocatableCode())3550{3551comp()->failCompilation<J9::AOTHasInvokeHandle>("COMPILATION_AOT_HAS_INVOKEHANDLE 2");3552}35533554if (comp()->getOption(TR_FullSpeedDebug) && !isPeekingMethod())3555comp()->failCompilation<J9::FSDHasInvokeHandle>("FSD_HAS_INVOKEHANDLE 2");35563557TR::SymbolReference * invokeGenericSymRef = symRefTab()->findOrCreateHandleMethodSymbol(_methodSymbol, cpIndex);3558TR::Method *invokeGeneric = invokeGenericSymRef->getSymbol()->castToMethodSymbol()->getMethod();3559TR::SymbolReference *invokeExactOriginal = symRefTab()->methodSymRefFromName(_methodSymbol,3560JSR292_MethodHandle, JSR292_invokeExact, JSR292_invokeExactSig, TR::MethodSymbol::ComputedVirtual, invokeGenericSymRef->getCPIndex());3561TR::SymbolReference *invokeExactSymRef = symRefTab()->methodSymRefWithSignature(3562invokeExactOriginal, invokeGeneric->signatureChars(), invokeGeneric->signatureLength());35633564TR::Node* callNode = genInvokeHandle(invokeExactSymRef);35653566_invokeHandleGenericCalls->set(_bcIndex);3567return callNode;3568}35693570TR::Node*3571TR_J9ByteCodeIlGenerator::genOrFindAdjunct(TR::Node* node)3572{3573TR::Node *adjunct;3574if (node->getOpCode().isLoadDirect())3575{3576// need to get adjunct symbol corresponding to this symbol, and create a load for it3577TR::SymbolReference* symRef = node->getSymbolReference();3578TR::DataType type = symRef->getSymbol()->getDataType();3579int32_t slot = symRef->getCPIndex();3580loadAuto(type, slot, true);3581adjunct = pop();3582}3583else3584{3585// expect that adjunct part is third child of node3586TR_ASSERT(node->isDualHigh() || node->isSelectHigh(),3587"this node should be a dual or select, where the adjunct part of the answer is in the third child");3588adjunct = node->getChild(2);3589if (node->isSelectHigh())3590{3591adjunct = adjunct->getFirstChild();3592}3593}3594return adjunct;3595}35963597#define STOPME \3598{\3599static int stopped = 0; \3600if (!stopped) \3601{\3602genDebugCmd(__FILE__, __LINE__);\3603stopped = 1;\3604}\3605}36063607// Definition of operation to be executed when converting the non standard lengths3608struct OperationDescriptor3609{3610int32_t shiftDistance; // distance to shift, the direction depends on load or store3611int32_t offsetAdjustment; // adjustment of the memory offset3612int32_t lengthNew; // new length to be stored or loaded3613};3614static void printOp(char *tags, struct OperationDescriptor *op)3615{3616printf("[%s] shift:%d, ajdust:%d, length:%d\n",3617tags?tags:"OP",3618op->shiftDistance, op->offsetAdjustment,3619op->lengthNew);3620}36213622static struct OperationDescriptor opsLength3[] =3623{3624{0,2,1},{8,0,2}, // big-endian3625{0,0,1},{8,1,2} // little-endian3626};3627static struct OperationDescriptor opsLength5[] =3628{3629{0,4,1}, {8,0,4}, // big-endian3630{0,0,1}, {8,1,4} // little-endian3631};3632static struct OperationDescriptor opsLength6[] =3633{3634{0,4,2}, {16,0,4}, // big-endian3635{0,0,2}, {16,2,4} // little-endian3636};3637static struct OperationDescriptor opsLength7[] =3638{3639{0,6,1}, {8,4,2}, {24,0,4}, // big-endian3640{0,0,1}, {8,1,2}, {24,3,4} // little-endian3641};3642static struct OperationDescriptor *opsNonStandardLengths[] =3643{ 0, 0, 0, opsLength3, 0, opsLength5, opsLength6, opsLength7 };3644static int32_t numOpsNonStandardLengths[] =3645{ 0, 0, 0, 2, 0, 2, 2, 3};36463647TR::Node *3648TR_J9ByteCodeIlGenerator::getReceiverFor(TR::SymbolReference *symRef)3649{3650TR::Method * method = symRef->getSymbol()->castToMethodSymbol()->getMethod();3651int32_t receiverDepth = method->numberOfExplicitParameters(); // look past all the explicit arguments3652return _stack->element(_stack->topIndex() - receiverDepth);3653}36543655TR::Node *3656TR_J9ByteCodeIlGenerator::genInvokeWithVFTChild(TR::SymbolReference *symRef)3657{3658TR::Node *receiver = getReceiverFor(symRef);3659TR::Node *vftLoad = TR::Node::createWithSymRef(TR::aloadi, 1, 1, receiver, symRefTab()->findOrCreateVftSymbolRef());3660return genInvoke(symRef, vftLoad);3661}36623663366436653666TR::Node*3667TR_J9ByteCodeIlGenerator::genInvoke(TR::SymbolReference * symRef, TR::Node *indirectCallFirstChild, TR::Node *invokedynamicReceiver)3668{3669TR::MethodSymbol * symbol = symRef->getSymbol()->castToMethodSymbol();3670bool isStatic = symbol->isStatic();3671bool isDirectCall = indirectCallFirstChild == NULL;36723673TR::Method * calledMethod = symbol->getMethod();3674int32_t numArgs = calledMethod->numberOfExplicitParameters() + (isStatic ? 0 : 1);36753676TR::ILOpCodes opcode = TR::BadILOp;3677switch (symbol->getRecognizedMethod())3678{3679case TR::java_lang_Integer_valueOf:3680// TODO: It's gross that ilgen knows what a dememoization opportunity is. This should be refactored.3681_methodSymbol->setHasDememoizationOpportunities(true);3682break;3683default:3684break;3685}36863687if (comp()->cg()->getSupportsBitOpCodes() && !comp()->getOption(TR_DisableBitOpcode))3688{3689switch (symbol->getRecognizedMethod())3690{3691case TR::java_lang_Integer_highestOneBit:3692opcode = TR::ihbit;3693break;3694case TR::java_lang_Integer_lowestOneBit:3695if(comp()->target().cpu.isX86() || comp()->target().cpu.isARM64())3696opcode = TR::ilbit;3697else3698opcode = TR::BadILOp;3699break;3700case TR::java_lang_Integer_numberOfLeadingZeros:3701opcode = TR::inolz;3702break;3703case TR::java_lang_Integer_numberOfTrailingZeros:3704opcode = TR::inotz;3705break;3706case TR::java_lang_Integer_bitCount:3707if (comp()->target().cpu.hasPopulationCountInstruction())3708opcode = TR::ipopcnt;3709else3710opcode = TR::BadILOp;3711break;3712case TR::java_lang_Long_highestOneBit:3713opcode = TR::lhbit;3714break;3715case TR::java_lang_Long_lowestOneBit:3716if(comp()->target().cpu.isX86() || comp()->target().cpu.isARM64())3717opcode = TR::llbit;3718else3719opcode = TR::BadILOp;3720break;3721case TR::java_lang_Long_numberOfLeadingZeros:3722opcode = TR::lnolz;3723break;3724case TR::java_lang_Long_numberOfTrailingZeros:3725opcode = TR::lnotz;3726break;3727case TR::java_lang_Long_bitCount:3728if (comp()->target().cpu.hasPopulationCountInstruction())3729opcode = TR::lpopcnt;3730else3731opcode = TR::BadILOp;3732break;3733default:3734break;3735}3736}37373738if (opcode != TR::BadILOp)3739{3740performTransformation(comp(), "O^O BIT OPCODE: convert call to method %s to bit opcode\n",calledMethod->signature(trMemory()));3741TR::Node * node = TR::Node::create(opcode, 1);3742node->setAndIncChild(0, pop());3743push(node);3744return node;3745}37463747#if !defined(TR_HOST_ARM) && !defined(TR_HOST_ARM64)37483749if (comp()->supportsQuadOptimization())3750{3751// Under DLT, the Quad opts don't work because the interpreted Quad3752// operations will produce Quad objects, but the jitted ones will assume3753// they have been turned into longs.37543755switch (symbol->getRecognizedMethod())3756{3757case TR::com_ibm_Compiler_Internal_Quad_enableQuadOptimization:3758{3759// Quad opts have the potential to make things way worse if we3760// don't recognize the methods and special-case them here. However,3761// if we recognize enableQuadOptimizations, we should have no trouble3762// recognizing the rest.3763//3764loadConstant(TR::iconst, 1);3765return _stack->top();3766}3767case TR::com_ibm_Compiler_Internal_Quad_mul_ll:3768{3769// lumulh main operator3770// x3771// y3772// lmul adjunct3773// ==> x3774// ==> y3775TR::Node* y = pop();3776TR::Node* x = pop();3777TR::Node* lmul = TR::Node::create(TR::lmul, 2, x, y);3778TR::Node* lumulh = TR::Node::create(TR::lumulh, 3, x, y, lmul);3779push(lumulh);3780return lumulh;3781break;3782}3783case TR::com_ibm_Compiler_Internal_Quad_hi:3784{3785// hi(w)3786TR::Node* wh = pop();3787push(wh);3788return wh;3789break;3790}3791case TR::com_ibm_Compiler_Internal_Quad_lo:3792{3793// lo(w)3794TR::Node* wh = pop();3795TR::Node* wl = genOrFindAdjunct(wh);3796push(wl);3797return wl;3798break;3799}3800case TR::com_ibm_Compiler_Internal_Quad_add_ll:3801{3802// add two unsigned longs to produce a quad3803//3804// luaddc main operator3805// lconst 03806// lconst 03807// computeCC3808// ladd adjunct operator3809// x3810// y3811TR::Node* y = pop();3812TR::Node* x = pop();3813TR::Node* zero = TR::Node::create(TR::lconst, 0, 0);3814TR::Node* ladd = TR::Node::create(TR::ladd, 2, x, y);3815TR::Node* carry = TR::Node::create(TR::computeCC, 1, ladd);3816TR::Node* luaddc = TR::Node::create(TR::luaddc, 3, zero, zero, carry);3817push(luaddc);3818return luaddc;3819break;3820}3821case TR::com_ibm_Compiler_Internal_Quad_add_ql:3822{3823// luaddc main operator3824// wh3825// lconst 03826// computeCC3827// ladd adjunct operator3828// wl3829// x3830TR::Node* x = pop();3831TR::Node* wh = pop();3832TR::Node* wl = genOrFindAdjunct(wh);3833TR::Node* zero = TR::Node::create(TR::lconst, 0, 0);3834TR::Node* ladd = TR::Node::create(TR::ladd, 2, wl, x);3835TR::Node* carry = TR::Node::create(TR::computeCC, 1, ladd);3836TR::Node* luaddc = TR::Node::create(TR::luaddc, 3, wh, zero, carry);3837push(luaddc);3838return luaddc;3839break;3840}3841case TR::com_ibm_Compiler_Internal_Quad_sub_ll:3842{3843// sub two unsigned longs to produce a quad3844//3845// lusubb main operator3846// lconst 03847// lconst 03848// computeCC3849// lsub adjunct operator3850// x3851// y3852TR::Node* y = pop();3853TR::Node* x = pop();3854TR::Node* zero = TR::Node::create(TR::lconst, 0, 0);3855TR::Node* lsub = TR::Node::create(TR::lsub, 2, x, y);3856TR::Node* borrow = TR::Node::create(TR::computeCC, 1, lsub);3857TR::Node* lusubb = TR::Node::create(TR::lusubb, 3, zero, zero, borrow);3858push(lusubb);3859return lusubb;3860break;3861}3862case TR::com_ibm_Compiler_Internal_Quad_sub_ql:3863{3864// lusubb main operator3865// wh3866// lconst 03867// computeCC3868// lsub adjunct operator3869// wl3870// x3871TR::Node* x = pop();3872TR::Node* wh = pop();3873TR::Node* wl = genOrFindAdjunct(wh);3874TR::Node* zero = TR::Node::create(TR::lconst, 0, 0);3875TR::Node* lsub = TR::Node::create(TR::lsub, 2, wl, x);3876TR::Node* borrow = TR::Node::create(TR::computeCC, 1, lsub);3877TR::Node* lusubb = TR::Node::create(TR::lusubb, 3, wh, zero, borrow);3878push(lusubb);3879return lusubb;3880break;3881}3882default:3883break;3884}3885}3886#endif38873888if (symbol->getRecognizedMethod() == TR::com_ibm_Compiler_Internal__TR_Prefetch)3889{3890TR::Node *node = NULL;38913892if ((comp()->getOptLevel() < hot))3893{3894int i = 0;3895for (i=0; i<numArgs; i++)3896genTreeTop(pop());3897return node;3898}38993900// Get the type of prefetch3901PrefetchType prefetchType = NoPrefetch;3902TR::Method *method = symbol->castToMethodSymbol()->getMethod();3903if (method->nameLength() == 15 && !strncmp(method->nameChars(), "_TR_Release_All", 15))3904{3905prefetchType = ReleaseAll;3906}3907else if (method->nameLength() == 17 && !strncmp(method->nameChars(), "_TR_Prefetch_Load", 17))3908{3909prefetchType = PrefetchLoad;3910}3911else if (method->nameLength() == 18 && !strncmp(method->nameChars(), "_TR_Prefetch_Store", 18))3912{3913prefetchType = PrefetchStore;3914}3915else if (method->nameLength() == 20)3916{3917if (!strncmp(method->nameChars(), "_TR_Prefetch_LoadNTA", 20))3918prefetchType = PrefetchLoadNonTemporal;3919else if (!strncmp(method->nameChars(), "_TR_Prefetch_Load_L1", 20))3920prefetchType = PrefetchLoadL1;3921else if (!strncmp(method->nameChars(), "_TR_Prefetch_Load_L2", 20))3922prefetchType = PrefetchLoadL2;3923else if (!strncmp(method->nameChars(), "_TR_Prefetch_Load_L3", 20))3924prefetchType = PrefetchLoadL3;3925}3926else if (method->nameLength() == 21)3927{3928if (!strncmp(method->nameChars(), "_TR_Prefetch_StoreNTA", 21))3929prefetchType = PrefetchStoreNonTemporal;3930else if (!strncmp(method->nameChars(), "_TR_Release_StoreOnly", 21))3931prefetchType = ReleaseStore;3932}3933else if (method->nameLength() == 29 && !strncmp(method->nameChars(), "_TR_Prefetch_StoreConditional", 29))3934{3935prefetchType = PrefetchStoreConditional;3936}39373938TR::Node *n2 = pop();3939if (2 == numArgs && n2->getOpCode().isInt())3940{3941node = TR::Node::createWithSymRef(TR::Prefetch, 4, symRef);3942TR::Node *addrNode = pop();39433944// For constant 2nd arguments, we'll add it to the offset.3945if (n2->getOpCode().isLoadConst())3946{3947// TR::Prefetch 1st child: address3948node->setAndIncChild(0, addrNode);3949// TR::Prefetch 2nd child: offset3950node->setAndIncChild(1, n2);3951}3952else3953{3954// TR::Prefetch 1st child: address3955// aiadd3956// addrNode3957// offsetNode3958TR::Node * aiaddNode = TR::Node::create(TR::aiadd, 2, addrNode, n2);3959node->setAndIncChild(0, aiaddNode);39603961// TR::Prefetch 2nd child: Set offset to be zero.3962TR::Node * offsetNode = TR::Node::create(TR::iconst, 0, 0);3963node->setAndIncChild(1, offsetNode);3964}39653966// TR::Prefetch 3rd child : size3967TR::Node * size = TR::Node::create(TR::iconst, 0, 1);3968node->setAndIncChild(2, size);39693970// TR::Prefetch 4th child : type3971TR::Node * type = TR::Node::create(TR::iconst, 0, (int32_t)prefetchType);3972node->setAndIncChild(3, type);39733974genTreeTop(node);3975}3976else if (3 == numArgs || 2 == numArgs)3977{3978TR::Node * n3 = n2; // it's already popped above3979TR::Node * n2 = pop();3980TR::Node * n1 = (numArgs == 3) ? pop() : NULL;39813982if (n3->getSymbolReference() &&3983n3->getSymbolReference()->getSymbol()->isStatic() &&3984n3->getSymbolReference()->getSymbol()->castToStaticSymbol()->isConstString() &&3985n2->getSymbolReference() &&3986n2->getSymbolReference()->getSymbol()->isStatic() &&3987n2->getSymbolReference()->getSymbol()->castToStaticSymbol()->isConstString())3988{3989uintptr_t offset = fej9()->getFieldOffset(comp(), n2->getSymbolReference(), n3->getSymbolReference() );3990if (offset)3991{3992TR::Node * n ;3993if (comp()->target().is32Bit() ||3994(int32_t)(((uint32_t)((uint64_t)offset >> 32)) & 0xffffffff) == (uint32_t)0)3995{3996n = TR::Node::create(TR::iconst, 0, offset);3997}3998else3999{4000n = TR::Node::create(TR::lconst, 0, 0);4001n->setLongInt(offset);4002}4003if (numArgs == 3)4004{4005node = TR::Node::createWithSymRef(TR::Prefetch, 4, symRef);4006node->setAndIncChild(1, n);4007node->setAndIncChild(0, n1);4008}4009else4010{4011node = TR::Node::createWithSymRef(TR::Prefetch, 4, symRef);4012node->setAndIncChild(0, n);4013TR::Node * offsetNode = TR::Node::create(TR::iconst, 0, 0);4014node->setAndIncChild(1, offsetNode);4015}40164017// TR::Prefetch 3rd child : size4018TR::Node * size = TR::Node::create(TR::iconst, 0, 1);4019node->setAndIncChild(2, size);40204021// TR::Prefetch 4th child : type4022TR::Node * type = TR::Node::create(TR::iconst, 0, (int32_t)prefetchType);4023node->setAndIncChild(3, type);40244025genTreeTop(node);4026}4027else4028{4029// Generate treetops to retain proper reference count.4030genTreeTop(n2);4031genTreeTop(n3);4032if (n1)4033genTreeTop(n1);40344035traceMsg(comp(),"Prefetch: Unable to resolve offset.\n");4036}4037}4038}4039else4040{4041TR_ASSERT(0, "TR::Prefetch does not have two or three children");4042}40434044return node;4045}40464047#define DAA_PRINT(a) \4048case a: \4049if(trace()) \4050traceMsg(comp(), "DAA Method found: %s\n", #a); \4051break40524053//print out the method name and ILCode from the4054switch (symbol->getRecognizedMethod())4055{4056DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayMarshaller_writeShort);4057DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayMarshaller_writeShortLength);4058DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayMarshaller_writeInt);4059DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayMarshaller_writeIntLength);4060DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayMarshaller_writeLong);4061DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayMarshaller_writeLongLength);4062DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayMarshaller_writeFloat);4063DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayMarshaller_writeDouble);40644065DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayUnmarshaller_readShort);4066DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayUnmarshaller_readShortLength);4067DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayUnmarshaller_readInt);4068DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayUnmarshaller_readIntLength);4069DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayUnmarshaller_readLong);4070DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayUnmarshaller_readLongLength);4071DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayUnmarshaller_readFloat);4072DAA_PRINT(TR::com_ibm_dataaccess_ByteArrayUnmarshaller_readDouble);40734074DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_JITIntrinsicsEnabled);40754076DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertIntegerToPackedDecimal);4077DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertIntegerToPackedDecimal_ByteBuffer);4078DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertPackedDecimalToInteger);4079DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertPackedDecimalToInteger_ByteBuffer);40804081DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertLongToPackedDecimal);4082DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertLongToPackedDecimal_ByteBuffer);4083DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertPackedDecimalToLong);4084DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertPackedDecimalToLong_ByteBuffer);40854086DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertExternalDecimalToPackedDecimal);4087DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertPackedDecimalToExternalDecimal);40884089DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertUnicodeDecimalToPackedDecimal);4090DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertPackedDecimalToUnicodeDecimal);40914092DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertLongToExternalDecimal);4093DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertExternalDecimalToLong);40944095DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertIntegerToExternalDecimal);4096DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertExternalDecimalToInteger);40974098DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertUnicodeDecimalToInteger);4099DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertIntegerToUnicodeDecimal);41004101DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertUnicodeDecimalToLong);4102DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertLongToUnicodeDecimal);41034104DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertPackedDecimalToBigInteger);4105DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertBigIntegerToPackedDecimal);41064107DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertExternalDecimalToBigInteger);4108DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertBigIntegerToExternalDecimal);41094110DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertUnicodeDecimalToBigInteger);4111DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertBigIntegerToUnicodeDecimal);41124113DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertBigDecimalToPackedDecimal);4114DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertPackedDecimalToBigDecimal);41154116DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertBigDecimalToExternalDecimal);4117DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertExternalDecimalToBigDecimal);41184119DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertBigDecimalToUnicodeDecimal);4120DAA_PRINT(TR::com_ibm_dataaccess_DecimalData_convertUnicodeDecimalToBigDecimal);41214122DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_addPackedDecimal);4123DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_subtractPackedDecimal);4124DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_multiplyPackedDecimal);4125DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_dividePackedDecimal);4126DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_remainderPackedDecimal);4127DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_greaterThanPackedDecimal);4128DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_greaterThanOrEqualsPackedDecimal);4129DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_lessThanPackedDecimal);4130DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_lessThanOrEqualsPackedDecimal);4131DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_equalsPackedDecimal);4132DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_notEqualsPackedDecimal);41334134DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_checkPackedDecimal);4135DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_checkPackedDecimal_2bInlined2);4136DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_checkPackedDecimal_2bInlined1);4137DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_shiftLeftPackedDecimal);4138DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_shiftRightPackedDecimal);4139DAA_PRINT(TR::com_ibm_dataaccess_PackedDecimal_movePackedDecimal);41404141default:4142break;4143}41444145if(symbol->getRecognizedMethod() == TR::com_ibm_dataaccess_DecimalData_JITIntrinsicsEnabled)4146{4147bool isZLinux = comp()->target().isLinux() && comp()->target().cpu.isZ();4148int32_t constVal = (comp()->target().isZOS() || isZLinux) &&4149!comp()->getOption(TR_DisablePackedDecimalIntrinsics) ? 1 : 0;41504151loadConstant(TR::iconst, constVal);4152return NULL;4153}41544155/**4156* java/lang/invoke/MethodHandleImpl.profileBoolean() performs some internal profiling4157* on the boolean parameter value before returning it. Since the OpenJ9 JIT does not4158* consume that profiling information the profiling overhead is not necessary. Eliminate4159* the call and simply replace it with a reference to the boolean parameter.4160*/4161if (symbol->getRecognizedMethod() == TR::java_lang_invoke_MethodHandleImpl_profileBoolean)4162{4163pop();4164TR::Node *resultNode = _stack->top();4165genTreeTop(resultNode);4166return resultNode;4167}41684169// Can't use recognized methods since it's not enabled on AOT4170//if (symbol->getRecognizedMethod() == TR::com_ibm_rmi_io_FastPathForCollocated_isVMDeepCopySupported)4171int32_t len = calledMethod->classNameLength();4172char * s = TR::Compiler->cls.classNameToSignature(calledMethod->classNameChars(), len, comp());41734174if (strstr(s, "com/ibm/rmi/io/FastPathForCollocated") &&4175!strncmp(calledMethod->nameChars(), "isVMDeepCopySupported", calledMethod->nameLength()))4176{4177loadConstant(TR::iconst, 1);4178return NULL;4179}4180else if (!strncmp(comp()->getCurrentMethod()->classNameChars(), "com/ibm/jit/JITHelpers", 22))4181{4182// fast pathing for JITHelpers4183//4184// do not do this transformation if the current method is com/ibm/jit/JITHelpers.is32Bit4185// inlineNativeCall will take care of doing the right thing4186//4187bool isCall32bit = false;4188if (strstr(s, "com/ibm/jit/JITHelpers") &&4189!strncmp(calledMethod->nameChars(), "is32Bit", calledMethod->nameLength()))4190isCall32bit = true;4191#if 04192bool fold = true;4193if (!strncmp(comp()->getCurrentMethod()->nameChars(), "is32Bit", 7))4194fold = false;41954196if (fold && indirectCallFirstChild && isCall32bit)4197{4198// fold away the check if possible4199int32_t value = comp()->target().is64Bit() ? 0 : 1;4200loadConstant(TR::iconst, value);4201// cleanup the receiver because its not going to be used anymore4202//4203indirectCallFirstChild->incReferenceCount();4204indirectCallFirstChild->recursivelyDecReferenceCount();4205return NULL;4206}4207#endif4208}42094210if (comp()->cg()->getSupportsInlineConcurrentLinkedQueue() && (TR::Compiler->om.writeBarrierType() != gc_modron_wrtbar_satb) &&4211(symbol->getRecognizedMethod() == TR::java_util_concurrent_ConcurrentLinkedQueue_tmEnabled))4212{4213loadConstant(TR::iconst, 1);4214return NULL;4215}42164217if (symbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_supportsIntrinsicCaseConversion)4218{4219pop(); //pop the receiver since it's not used4220loadConstant(TR::iconst, cg()->getSupportsInlineStringCaseConversion() ? 1 : 0);4221return NULL;4222}42234224if (!isStatic && _classInfo && !symRef->isUnresolved())4225{4226if (!_classInfo->getFieldInfo())4227performClassLookahead(_classInfo);42284229int32_t len = calledMethod->classNameLength();4230char * s = TR::Compiler->cls.classNameToSignature(calledMethod->classNameChars(), len, comp());42314232TR::Node * thisObject = invokedynamicReceiver ? invokedynamicReceiver : _stack->element(_stack->topIndex() - (numArgs-1));4233TR_PersistentFieldInfo * fieldInfo = _classInfo->getFieldInfo() ? _classInfo->getFieldInfo()->findFieldInfo(comp(), thisObject, false) : NULL;4234if (fieldInfo && fieldInfo->isTypeInfoValid())4235{4236if (fieldInfo->getNumChars() == len && !memcmp(s, fieldInfo->getClassPointer(), len))4237{4238if (performTransformation(comp(), "O^O CLASS LOOKAHEAD: Devirtualizing call to method %s on receiver object %p which has type %.*s based on class file examination\n", calledMethod->signature(trMemory()), thisObject, len, s))4239isDirectCall = true;4240}4241}4242else if (fieldInfo &&4243fieldInfo->isBigDecimalType())4244{4245if (22 == len && !memcmp(s, "Ljava/math/BigDecimal;", len))4246{4247if (performTransformation(comp(), "O^O CLASS LOOKAHEAD: Devirtualizing call to method %s on receiver object %p which has type %.*s based on class file examination\n", calledMethod->signature(trMemory()), thisObject, len, s))4248isDirectCall = true;4249}4250}4251else if (fieldInfo &&4252fieldInfo->isBigIntegerType())4253{4254if (22 == len && !memcmp(s, "Ljava/math/BigInteger;", len))4255{4256if (performTransformation(comp(), "O^O CLASS LOOKAHEAD: Devirtualizing call to method %s on receiver object %p which has type %.*s based on class file examination\n", calledMethod->signature(trMemory()), thisObject, len, s))4257isDirectCall = true;4258}4259}4260}42614262TR::Node * callNode;4263TR::Node * receiver = 0;4264if (isDirectCall)4265{4266TR::ILOpCodes callOpCode = calledMethod->directCallOpCode();4267TR::ResolvedMethodSymbol *resolvedMethodSymbol = symbol->getResolvedMethodSymbol();4268bool needToGenAndPop = false;4269if (resolvedMethodSymbol)4270{4271if (resolvedMethodSymbol->getRecognizedMethod() == TR::java_lang_Class_newInstanceImpl && // the method being called4272_methodSymbol->getRecognizedMethod() == TR::java_lang_Class_newInstance && // method we are doing genIl for4273comp()->getJittedMethodSymbol()->getRecognizedMethod() != TR::java_lang_Class_newInstance && // method we are compiling4274!isPeekingMethod() &&4275cg()->getSupportsNewInstanceImplOpt() &&4276!comp()->getOption(TR_DisableInliningOfNatives) &&4277!comp()->compileRelocatableCode() && // disable when AOTing4278!comp()->getOptions()->realTimeGC() &&4279!comp()->getOption(TR_DisableNewInstanceImplOpt)) // the caller of Class.newInstance()4280{4281TR_ASSERT(numArgs == 1, "unexpected numChildren on newInstanceImpl call");4282callNode = genNewInstanceImplCall(pop());4283calledMethod = callNode->getSymbolReference()->getSymbol()->castToMethodSymbol()->getMethod();4284}4285else4286needToGenAndPop = true;4287}4288else4289needToGenAndPop = true;42904291if (needToGenAndPop)4292{4293callNode = genNodeAndPopChildren(callOpCode, numArgs, symRef);4294}4295if (!isStatic)4296receiver = callNode->getChild(0);4297if (receiver && receiver->isThisPointer())4298{4299callNode->getByteCodeInfo().setIsSameReceiver(1);4300}4301}4302else4303{4304TR::ILOpCodes callOpCode = calledMethod->indirectCallOpCode();4305if (invokedynamicReceiver)4306{4307// invokedynamic is an oddball. It's the only way to invoke a method4308// such that the receiver is NOT on the operand stack, yet it IS4309// included in the numArgs calculation. That's why we pass4310// numChildren as numArgs+1 below.4311//4312callNode = genNodeAndPopChildren(callOpCode, numArgs + 1, symRef, 2);4313callNode->setAndIncChild(0, indirectCallFirstChild);4314callNode->setAndIncChild(1, invokedynamicReceiver);4315}4316else4317{4318callNode = genNodeAndPopChildren(callOpCode, numArgs + 1, symRef, 1);4319callNode->setAndIncChild(0, indirectCallFirstChild);4320}43214322if (!isStatic)4323receiver = callNode->getChild(1);43244325if (receiver && receiver->isThisPointer())4326{4327callNode->getByteCodeInfo().setIsSameReceiver(1);4328}4329}43304331if (cg()->getSupportsInlineStringCaseConversion() &&4332(symbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_toUpperIntrinsicLatin1 ||4333symbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_toLowerIntrinsicLatin1 ||4334symbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_toUpperIntrinsicUTF16 ||4335symbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_toLowerIntrinsicUTF16))4336{4337isDirectCall = true;4338}43394340if (!comp()->getOption(TR_DisableSIMDDoubleMaxMin))4341{4342bool platformSupported = comp()->target().cpu.isZ();4343bool vecInstrAvailable = cg()->getSupportsVectorRegisters();43444345if (platformSupported && vecInstrAvailable &&4346(symbol->getRecognizedMethod() == TR::java_lang_Math_max_D ||4347symbol->getRecognizedMethod() == TR::java_lang_Math_min_D))4348{4349isDirectCall = true;4350}4351}435243534354if (comp()->getOptions()->getEnableGPU(TR_EnableGPU) &&4355strcmp(symbol->getMethod()->signature(trMemory()),4356"java/util/stream/IntStream.forEach(Ljava/util/function/IntConsumer;)V") == 0) // might not be resolved4357{4358//This prevents recompilation at profiled very hot which also prevents the method from reaching scorching4359//If JIT GPU works with profiled very hot or scorching in the future, this can be removed.4360TR::Recompilation *recompilationInfo = comp()->getRecompilationInfo();4361if (recompilationInfo)4362recompilationInfo->getJittedBodyInfo()->setDisableSampling(true);43634364comp()->setHasIntStreamForEach();43654366if (comp()->getOptLevel() < scorching &&4367!comp()->getOptimizationPlan()->getDontFailOnPurpose())4368{4369comp()->failCompilation<J9::LambdaEnforceScorching>("Enforcing optLevel=scorching");4370}4371}43724373// fast pathing for ORB readObject optimization4374//4375bool canDoSerializationOpt = true;4376if (callNode && callNode->getOpCode().hasSymbolReference() && !callNode->getSymbolReference()->isUnresolved() &&4377(_methodSymbol->getResolvedMethod()->nameLength() == ORB_CALLER_METHOD_NAME_LEN) &&4378!strncmp(_methodSymbol->getResolvedMethod()->nameChars(), ORB_CALLER_METHOD_NAME, ORB_CALLER_METHOD_NAME_LEN) &&4379(_methodSymbol->getResolvedMethod()->signatureLength() == ORB_CALLER_METHOD_SIG_LEN) &&4380!strncmp(_methodSymbol->getResolvedMethod()->signatureChars(), ORB_CALLER_METHOD_SIG, ORB_CALLER_METHOD_SIG_LEN))4381{4382if (comp()->getOption(TR_TraceILGen))4383traceMsg(comp(), "handling callNode %p, current method %s\n", callNode, _methodSymbol->getResolvedMethod()->signature(trMemory()));43844385TR::Node *receiver = callNode->getFirstArgument();4386if (receiver && receiver->getOpCode().hasSymbolReference() && receiver->getSymbol()->isParm() && !receiver->isThisPointer() &&4387(calledMethod->nameLength() == ORB_CALLEE_METHOD_NAME_LEN) &&4388!strncmp(calledMethod->nameChars(), ORB_CALLEE_METHOD_NAME, ORB_CALLEE_METHOD_NAME_LEN) &&4389(calledMethod->signatureLength() == ORB_CALLEE_METHOD_SIG_LEN) &&4390!strncmp(calledMethod->signatureChars(), ORB_CALLEE_METHOD_SIG, ORB_CALLEE_METHOD_SIG_LEN))4391{4392TR_OpaqueClassBlock *cl = _methodSymbol->getResolvedMethod()->containingClass();43934394if (comp()->getOption(TR_TraceILGen))4395traceMsg(comp(), "called method %s, containing class %p\n", calledMethod->signature(trMemory()), cl);43964397bool isClassInitialized = false;4398TR_PersistentClassInfo * classInfo = comp()->getPersistentInfo()->getPersistentCHTable()->findClassInfoAfterLocking(cl, comp());4399if (classInfo && classInfo->isInitialized())4400isClassInitialized = true;44014402if (comp()->getOption(TR_TraceILGen))4403traceMsg(comp(), "isClassInitialized = %d\n", isClassInitialized);44044405if (isClassInitialized)4406{4407TR_OpaqueClassBlock *orbClass = fej9()->getClassFromSignature(ORB_REPLACE_CLASS_NAME, ORB_REPLACE_CLASS_LEN, callNode->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod());44084409if (comp()->getOption(TR_TraceILGen))4410traceMsg(comp(), "orbClass = %p, orbClassLoader %s systemClassLoader\n", orbClass, (!fej9()->isClassLoadedBySystemClassLoader(cl)) ? "!=" : "==");44114412// PR107804 if the ORB class is loaded we cannot do the serialization opt since the4413// ObjectInputStream.redirectedReadObject cannot handle ORB for some reason4414if (orbClass)4415{4416canDoSerializationOpt = false;4417}44184419if (orbClass && !fej9()->isClassLoadedBySystemClassLoader(cl))4420{4421TR_ScratchList<TR_ResolvedMethod> methods(trMemory());4422fej9()->getResolvedMethods(trMemory(), orbClass, &methods);4423ListIterator<TR_ResolvedMethod> it(&methods);4424TR_ResolvedMethod *replacementMethod;4425for (replacementMethod = it.getCurrent(); replacementMethod; replacementMethod = it.getNext())4426{4427if (replacementMethod->nameLength() == ORB_REPLACE_METHOD_NAME_LEN && !strncmp(replacementMethod->nameChars(), ORB_REPLACE_METHOD_NAME, ORB_REPLACE_METHOD_NAME_LEN))4428{4429if ((replacementMethod->signatureLength() == ORB_REPLACE_METHOD_SIG_LEN) &&4430!strncmp(replacementMethod->signatureChars(), ORB_REPLACE_METHOD_SIG, ORB_REPLACE_METHOD_SIG_LEN))4431break; // found it4432}4433}44344435if (replacementMethod)4436{4437if (performTransformation(comp(), "O^O ORB OPTIMIZATION : changing ObjectInputStream.readObject call to ORB redirectedReadObject\n"))4438{4439TR::Node *clazzLoad = TR::Node::createWithSymRef(TR::loadaddr, 0, symRefTab()->findOrCreateClassSymbol(_methodSymbol, 0, cl));4440TR::Node *jlClazzLoad = TR::Node::createWithSymRef(TR::aloadi, 1, 1, clazzLoad, symRefTab()->findOrCreateJavaLangClassFromClassSymbolRef());44414442push(receiver);4443push(jlClazzLoad);4444TR::SymbolReference *symRef = symRefTab()->findOrCreateMethodSymbol(_methodSymbol->getResolvedMethodIndex(), -1, replacementMethod, TR::MethodSymbol::Static);4445callNode = genNodeAndPopChildren(replacementMethod->directCallOpCode(), 2, symRef);4446isStatic = true;4447callNode->getChild(0)->recursivelyDecReferenceCount();4448}4449}4450}4451}4452}4453}44544455if (comp()->getOption(TR_TraceILGen))4456traceMsg(comp(), "considering callNode %p for java serialization optimization\n", callNode);4457if (canDoSerializationOpt && callNode && callNode->getOpCode().hasSymbolReference() && !callNode->getSymbolReference()->isUnresolved() &&4458callNode->getOpCode().isCallDirect())4459{4460if (comp()->getOption(TR_TraceILGen))4461traceMsg(comp(), "looking at receiver sig for callNode %p\n", callNode);4462TR::Node *receiver = callNode->getFirstArgument();4463if (receiver && receiver->getOpCode().hasSymbolReference())4464{4465TR::SymbolReference *receiverSymRef = receiver->getSymbolReference();4466int32_t receiverLen;4467const char *receiverSig = receiverSymRef->getTypeSignature(receiverLen);4468if (comp()->getOption(TR_TraceILGen))4469traceMsg(comp(), "handling callNode %p, receiver class name %s\n", callNode, receiverSig);4470if (receiverSig != NULL && (receiverLen == JAVA_SERIAL_CLASS_NAME_LEN) &&4471!strncmp(receiverSig, JAVA_SERIAL_CLASS_NAME, receiverLen))4472{4473if (comp()->getOption(TR_TraceILGen))4474traceMsg(comp(), "handling callNode %p, current method %s\n", callNode, _methodSymbol->getResolvedMethod()->signature(trMemory()));44754476if ((calledMethod->nameLength() == JAVA_SERIAL_CALLEE_METHOD_NAME_LEN) &&4477!strncmp(calledMethod->nameChars(), JAVA_SERIAL_CALLEE_METHOD_NAME, JAVA_SERIAL_CALLEE_METHOD_NAME_LEN) &&4478(calledMethod->signatureLength() == JAVA_SERIAL_CALLEE_METHOD_SIG_LEN) &&4479!strncmp(calledMethod->signatureChars(), JAVA_SERIAL_CALLEE_METHOD_SIG, JAVA_SERIAL_CALLEE_METHOD_SIG_LEN))4480{4481TR_OpaqueClassBlock *cl = _methodSymbol->getResolvedMethod()->containingClass();44824483if (comp()->getOption(TR_TraceILGen))4484traceMsg(comp(), "called method %s, containing class %p\n", calledMethod->signature(trMemory()), cl);4485bool isClassInitialized = false;4486TR_PersistentClassInfo * classInfo = comp()->getPersistentInfo()->getPersistentCHTable()->findClassInfoAfterLocking(cl, comp());4487if (classInfo && classInfo->isInitialized())4488isClassInitialized = true;4489if (comp()->getOption(TR_TraceILGen))4490traceMsg(comp(), "isClassInitialized = %d\n", isClassInitialized);4491if (isClassInitialized)4492{4493TR_OpaqueClassBlock *serialClass = fej9()->getClassFromSignature(JAVA_SERIAL_REPLACE_CLASS_NAME, JAVA_SERIAL_REPLACE_CLASS_LEN, callNode->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod());4494if (comp()->getOption(TR_TraceILGen))4495traceMsg(comp(), "serialClass = %p, serialClassLoader %s systemClassLoader\n", serialClass, (!fej9()->isClassLoadedBySystemClassLoader(cl)) ? "!=" : "==");4496if (serialClass && !fej9()->isClassLoadedBySystemClassLoader(cl))4497{4498TR_ScratchList<TR_ResolvedMethod> methods(trMemory());4499fej9()->getResolvedMethods(trMemory(), serialClass, &methods);4500ListIterator<TR_ResolvedMethod> it(&methods);4501TR_ResolvedMethod *replacementMethod;4502for (replacementMethod = it.getCurrent(); replacementMethod; replacementMethod = it.getNext())4503{4504if (replacementMethod->nameLength() == JAVA_SERIAL_REPLACE_METHOD_NAME_LEN && !strncmp(replacementMethod->nameChars(), JAVA_SERIAL_REPLACE_METHOD_NAME, JAVA_SERIAL_REPLACE_METHOD_NAME_LEN))4505{4506if ((replacementMethod->signatureLength() == JAVA_SERIAL_REPLACE_METHOD_SIG_LEN) &&4507!strncmp(replacementMethod->signatureChars(), JAVA_SERIAL_REPLACE_METHOD_SIG, JAVA_SERIAL_REPLACE_METHOD_SIG_LEN))4508break; // found it4509}4510}4511if (replacementMethod)4512{4513if (performTransformation(comp(), "O^O JAVA SERIALIZATION OPTIMIZATION : changing ObjectInputStream.readObject call to ObjectInputStream redirectedReadObject\n"))4514{4515TR::Node *clazzLoad = TR::Node::createWithSymRef(TR::loadaddr, 0, symRefTab()->findOrCreateClassSymbol(_methodSymbol, 0, cl));4516TR::Node *jlClazzLoad = TR::Node::createWithSymRef(TR::aloadi, 1, clazzLoad, 0, symRefTab()->findOrCreateJavaLangClassFromClassSymbolRef());4517push(receiver);4518push(jlClazzLoad);4519TR::SymbolReference *symRef = symRefTab()->findOrCreateMethodSymbol(_methodSymbol->getResolvedMethodIndex(), -1, replacementMethod, TR::MethodSymbol::Static);4520callNode = genNodeAndPopChildren(replacementMethod->directCallOpCode(), 2, symRef);4521isStatic = true;4522callNode->getChild(0)->recursivelyDecReferenceCount();4523}4524}4525}4526}4527}4528}4529}4530}45314532TR::Node *treeTopNode;4533if (isStatic || callNode->getChild(callNode->getFirstArgumentIndex())->isNonNull())4534{4535if (symRef->isUnresolved())4536treeTopNode = genResolveCheck(callNode);4537else4538treeTopNode = callNode;4539}4540else4541{4542if (symRef->isUnresolved())4543treeTopNode = genResolveAndNullCheck(callNode);4544else4545treeTopNode = genNullCheck(callNode);4546}45474548handleSideEffect(treeTopNode);45494550TR::TreeTop *callNodeTreeTop = NULL;4551if (symbol->getMandatoryRecognizedMethod() == TR::java_lang_invoke_ILGenMacros_placeholder)4552{4553// This call is not a real Java call. We can't put down a treetop for4554// it, or else that treetop will linger after the placeholder has been4555// expanded, at which point the placeholder call's children will all have4556// the wrong refcounts.4557}4558else4559{4560if (!_intrinsicErrorHandling)4561{4562callNodeTreeTop = genTreeTop(treeTopNode);4563}4564else4565{4566callNodeTreeTop = TR::TreeTop::create(comp(), treeTopNode);4567}4568_intrinsicErrorHandling = false;4569}45704571// The call may be transformed into a non-OSR point. Check if bookkeeping is needed4572// before the transformation.4573bool needOSRBookkeeping = false;4574int32_t osrInductionOffset;45754576// callNodeTreeTop may be null if this call should not be placed in the trees4577if (callNodeTreeTop4578&& comp()->getOption(TR_EnableOSR)4579&& !comp()->isPeekingMethod()4580&& comp()->isOSRTransitionTarget(TR::postExecutionOSR)4581&& comp()->isPotentialOSRPoint(callNodeTreeTop->getNode())4582&& !_methodSymbol->cannotAttemptOSRAt(callNode->getByteCodeInfo(), NULL, comp())4583&& !_cannotAttemptOSR)4584{4585needOSRBookkeeping = true;4586// callNode may become a non-OSR point after the transformation, calling getOSRInductionOffset4587// on a non-OSR point will trigger the assertion, thus get the induction offset here.4588osrInductionOffset = comp()->getOSRInductionOffset(callNode);4589}45904591TR::Node * resultNode = 0;45924593TR::ResolvedMethodSymbol * resolvedMethodSymbol = symbol->getResolvedMethodSymbol();459445954596// fast pathing for JITHelpers methods4597//4598if (!strncmp(comp()->getCurrentMethod()->classNameChars(), "com/ibm/jit/JITHelpers", 22))4599{4600bool isCallGetLength = false;4601bool isCallAddressAsPrimitive32 = false;4602bool isCallAddressAsPrimitive64 = false;4603if (strstr(s, "java/lang/reflect/Array") &&4604!strncmp(calledMethod->nameChars(), "getLength", calledMethod->nameLength()))4605isCallGetLength = true;4606///else if (strstr(s, "com/ibm/jit/JITHelpers") && resolvedMethodSymbol)4607else if (resolvedMethodSymbol)4608{4609/// (!strncmp(calledMethod->nameChars(), "getAddressAsPrimitive32", calledMethod->nameLength()) ||4610/// !strncmp(calledMethod->nameChars(), "getAddressAsPrimitive64", calledMethod->nameLength())))4611if (resolvedMethodSymbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_getAddressAsPrimitive32)4612isCallAddressAsPrimitive32 = true;4613else if (resolvedMethodSymbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_getAddressAsPrimitive64)4614isCallAddressAsPrimitive64 = true;4615}4616}46174618if (resolvedMethodSymbol &&4619!isPeekingMethod() &&4620(resolvedMethodSymbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_getJ9ClassFromObject32 ||4621resolvedMethodSymbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_getJ9ClassFromObject64))4622{4623TR::Node* obj = callNode->getChild(1);4624TR::Node* vftLoad = TR::Node::createWithSymRef(callNode, TR::aloadi, 1, obj, symRefTab()->findOrCreateVftSymbolRef());4625if (resolvedMethodSymbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_getJ9ClassFromObject32)4626{4627resultNode = TR::Node::create(callNode, TR::a2i, 1, vftLoad);4628}4629else4630{4631resultNode = TR::Node::create(callNode, TR::a2l, 1, vftLoad);4632}4633// Handle NullCHK4634if (callNodeTreeTop->getNode()->getOpCode().isNullCheck())4635TR::Node::recreate(callNodeTreeTop->getNode(), TR::treetop);4636callNodeTreeTop->getNode()->setAndIncChild(0, resultNode);4637// Decrement ref count for the call4638callNode->recursivelyDecReferenceCount();4639callNode = resultNode;4640}4641else if (resolvedMethodSymbol &&4642!isPeekingMethod() &&4643resolvedMethodSymbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_isArray)4644{4645TR::Node* obj = callNode->getChild(1);4646TR::Node* vftLoad = TR::Node::createWithSymRef(callNode, TR::aloadi, 1, obj, symRefTab()->findOrCreateVftSymbolRef());46474648if (comp()->target().is32Bit())4649{4650resultNode = TR::Node::createWithSymRef(callNode, TR::iloadi, 1, vftLoad, symRefTab()->findOrCreateClassAndDepthFlagsSymbolRef());4651}4652else4653{4654resultNode = TR::Node::createWithSymRef(callNode, TR::lloadi, 1, vftLoad, symRefTab()->findOrCreateClassAndDepthFlagsSymbolRef());4655resultNode = TR::Node::create(callNode, TR::l2i, 1, resultNode);4656}46574658int32_t andMask = comp()->fej9()->getFlagValueForArrayCheck();4659int32_t shiftAmount = trailingZeroes(andMask);4660resultNode = TR::Node::create(callNode, TR::iand, 2, resultNode, TR::Node::iconst(callNode, andMask));4661resultNode = TR::Node::create(callNode, TR::iushr, 2, resultNode, TR::Node::iconst(callNode, shiftAmount));4662// Handle NullCHK4663if (callNodeTreeTop->getNode()->getOpCode().isNullCheck())4664TR::Node::recreate(callNodeTreeTop->getNode(), TR::treetop);4665callNodeTreeTop->getNode()->setAndIncChild(0, resultNode);4666// Decrement ref count for the call4667callNode->recursivelyDecReferenceCount();4668callNode = resultNode;4669}4670else if (resolvedMethodSymbol &&4671resolvedMethodSymbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_getClassInitializeStatus &&4672!isPeekingMethod())4673{4674TR::Node* jlClass = callNode->getChild(1);4675TR::Node* j9Class = TR::Node::createWithSymRef(callNode, TR::aloadi, 1, jlClass, symRefTab()->findOrCreateClassFromJavaLangClassSymbolRef());46764677if (comp()->target().is32Bit())4678{4679resultNode = TR::Node::createWithSymRef(callNode, TR::iloadi, 1, j9Class, symRefTab()->findOrCreateInitializeStatusFromClassSymbolRef());4680}4681else4682{4683resultNode = TR::Node::createWithSymRef(callNode, TR::lloadi, 1, j9Class, symRefTab()->findOrCreateInitializeStatusFromClassSymbolRef());4684resultNode = TR::Node::create(callNode, TR::l2i, 1, resultNode);4685}46864687// Properly handle the checks4688if (callNodeTreeTop->getNode()->getOpCode().isNullCheck())4689TR::Node::recreate(callNodeTreeTop->getNode(), TR::treetop);4690callNodeTreeTop->getNode()->setAndIncChild(0, resultNode);4691// Decrement ref count for the call4692callNode->recursivelyDecReferenceCount();4693callNode = resultNode;4694}4695else if (symbol->isNative() && isDirectCall)4696{4697if (!comp()->getOption(TR_DisableInliningOfNatives) &&4698symbol->castToResolvedMethodSymbol()->getRecognizedMethod() != TR::unknownMethod)4699{4700if (!resultNode)4701{4702resultNode = fej9()->inlineNativeCall(comp(), callNodeTreeTop, callNode);4703}4704}47054706if (!resultNode)4707{4708if (symbol->isJNI())4709resultNode = callNode->processJNICall(callNodeTreeTop, _methodSymbol);4710else4711resultNode = callNode;4712}4713}4714else4715resultNode = callNode;47164717TR::DataType returnType = calledMethod->returnType();4718if (returnType != TR::NoType)4719{4720push(resultNode);4721}47224723if (needOSRBookkeeping)4724{4725saveStack(-1, !comp()->pendingPushLivenessDuringIlgen());4726stashPendingPushLivenessForOSR(osrInductionOffset);4727if (comp()->supportsInduceOSR() && comp()->getOSRMode() == TR::voluntaryOSR)4728{4729TR::Node* callToPotentialOSRPoint = TR::Node::createPotentialOSRPointHelperCallInILGen(callNodeTreeTop->getNode(), osrInductionOffset);4730_block->append(TR::TreeTop::create(comp(), TR::Node::create(TR::treetop, 1, callToPotentialOSRPoint)));4731}4732}47334734// We disable this optimization for JITServer because TR_VMField is not supported on JITServer yet. Once we have decided how to build the data structures4735// required by this optimization efficiently, we can re-enable this optimization.4736if (cg()->getEnforceStoreOrder() && calledMethod->isConstructor())4737{4738if (resolvedMethodSymbol4739#ifdef J9VM_OPT_JITSERVER4740&& !cg()->comp()->isOutOfProcessCompilation()4741#endif /* defined(J9VM_OPT_JITSERVER) */4742)4743{4744J9Class *methodClass = (J9Class *) resolvedMethodSymbol->getResolvedMethod()->containingClass();4745TR_VMFieldsInfo *fieldsInfoByIndex = new (comp()->trStackMemory()) TR_VMFieldsInfo(comp(), methodClass, 1, stackAlloc);4746ListIterator<TR_VMField> fieldIter(fieldsInfoByIndex->getFields());4747for (TR_VMField *field = fieldIter.getFirst(); field; field = fieldIter.getNext())4748{4749if ((field->modifiers & J9AccFinal) && methodClass == jitGetDeclaringClassOfROMField(comp()->j9VMThread(), methodClass, field->shape))4750{4751if (comp()->getOption(TR_TraceILGen))4752traceMsg(comp(), "added fence due to field %s \n", field->name);4753push(callNode->getFirstChild());4754genFlush(0);4755pop();4756break;4757}4758}4759}4760else4761{4762push(callNode->getFirstChild());4763genFlush(0);4764pop();4765}4766}47674768if (isDirectCall && indirectCallFirstChild)4769{4770// Not using the supplied node; must clean up its ref counts4771indirectCallFirstChild->incReferenceCount();4772indirectCallFirstChild->recursivelyDecReferenceCount();4773}47744775_intrinsicErrorHandling = false;4776return callNode;4777}47784779void4780TR_J9ByteCodeIlGenerator::chopPlaceholder(TR::Node *placeholder, int32_t firstChild, int32_t numChildren)4781{4782// Dec refcounts on the children we're going to drop. Also, find4783// start and end of the portion of the placeholder signature4784// describing the arguments we're going to keep.4785//4786int32_t i;4787for (i = 0; i < firstChild; i++)4788placeholder->getAndDecChild(i);4789for (i = placeholder->getNumChildren()-1; i >= firstChild + numChildren; i--)4790placeholder->getAndDecChild(i);47914792// Move the remaining children to the front.4793//4794for (i = 0; i < numChildren; i++)4795placeholder->setChild(i, placeholder->getChild(i + firstChild));4796placeholder->setNumChildren(numChildren);47974798// Edit signature4799//4800char *callSignature = placeholder->getSymbol()->castToMethodSymbol()->getMethod()->signatureChars();4801placeholder->setSymbolReference(symRefWithArtificialSignature(placeholder->getSymbolReference(),4802"(.-).$",4803callSignature, firstChild, firstChild + numChildren - 1,4804callSignature4805));4806}48074808bool4809TR_J9ByteCodeIlGenerator::runMacro(TR::SymbolReference * symRef)4810{4811// Give FE first kick at the can4812//4813if (runFEMacro(symRef))4814return true;48154816TR::MethodSymbol * symbol = symRef->getSymbol()->castToMethodSymbol();4817int32_t archetypeParmCount = symbol->getMethod()->numberOfExplicitParameters() + (symbol->isStatic() ? 0 : 1);48184819TR_ASSERT(symbol->isStatic(), "Macro methods must be static or else signature processing gets complicated by the implicit receiver");48204821switch (symRef->getSymbol()->castToMethodSymbol()->getMandatoryRecognizedMethod())4822{4823case TR::java_lang_invoke_ILGenMacros_numArguments:4824{4825if (!comp()->compileRelocatableCode())4826{4827TR::Node *argShepherd = genNodeAndPopChildren(TR::icall, 1, symRef);4828loadConstant(TR::iconst, argShepherd->getNumChildren());4829argShepherd->removeAllChildren();4830}4831return true;4832}4833case TR::java_lang_invoke_ILGenMacros_populateArray:4834{4835if (!comp()->compileRelocatableCode())4836{4837TR::Node *argShepherd = genNodeAndPopChildren(TR::icall, 1, symRef);4838TR::Node *array = pop();4839for (int32_t i = 0; i < argShepherd->getNumChildren(); i++)4840{4841TR::Node *arg = argShepherd->getChild(i);4842push(array);4843loadConstant(TR::iconst, i);4844push(arg);4845storeArrayElement(arg->getDataType()); // TODO:JSR292: use isstore for char arguments4846}4847argShepherd->removeAllChildren();4848push(array);4849}4850return true;4851}4852case TR::java_lang_invoke_ILGenMacros_first:4853{4854if (!comp()->compileRelocatableCode())4855{4856TR::Node *placeholder = genNodeAndPopChildren(TR::icall, 1, placeholderWithDummySignature());4857chopPlaceholder(placeholder, 0, 1);4858push(placeholder);4859}4860return true;4861}4862case TR::java_lang_invoke_ILGenMacros_last:4863{4864if (!comp()->compileRelocatableCode())4865{4866TR::Node *placeholder = genNodeAndPopChildren(TR::icall, 1, placeholderWithDummySignature());4867chopPlaceholder(placeholder, placeholder->getNumChildren()-1, 1);4868push(placeholder);4869}4870return true;4871}4872case TR::java_lang_invoke_ILGenMacros_firstN:4873{4874if (!comp()->compileRelocatableCode())4875{4876TR::Node *placeholder = genNodeAndPopChildren(TR::icall, 1, placeholderWithDummySignature());4877int32_t n = pop()->getInt();4878chopPlaceholder(placeholder, 0, n);4879push(placeholder);4880}4881return true;4882}4883case TR::java_lang_invoke_ILGenMacros_dropFirstN:4884{4885if (!comp()->compileRelocatableCode())4886{4887TR::Node *placeholder = genNodeAndPopChildren(TR::icall, 1, placeholderWithDummySignature());4888int32_t n = pop()->getInt();4889chopPlaceholder(placeholder, n, placeholder->getNumChildren()-n);4890push(placeholder);4891}4892return true;4893}4894case TR::java_lang_invoke_ILGenMacros_lastN:4895{4896if (!comp()->compileRelocatableCode())4897{4898TR::Node *placeholder = genNodeAndPopChildren(TR::icall, 1, placeholderWithDummySignature());4899int32_t n = pop()->getInt();4900chopPlaceholder(placeholder, placeholder->getNumChildren()-n, n);4901push(placeholder);4902}4903return true;4904}4905case TR::java_lang_invoke_ILGenMacros_middleN:4906{4907if (!comp()->compileRelocatableCode())4908{4909TR::Node *placeholder = genNodeAndPopChildren(TR::icall, 1, placeholderWithDummySignature());4910int32_t n = pop()->getInt();4911int32_t startIndex = pop()->getInt();4912chopPlaceholder(placeholder, startIndex, n);4913push(placeholder);4914}4915return true;4916}4917case TR::java_lang_invoke_ILGenMacros_rawNew:4918{4919if (!comp()->compileRelocatableCode())4920{4921push(TR::Node::createWithSymRef(TR::aloadi, 1, 1, pop(), symRefTab()->findOrCreateClassFromJavaLangClassSymbolRef()));4922genNew(TR::variableNew);4923}4924return true;4925}4926case TR::java_lang_invoke_ILGenMacros_push:4927{4928if (!comp()->compileRelocatableCode())4929shiftAndCopy(_stack->size(), 1);4930return true;4931}4932case TR::java_lang_invoke_ILGenMacros_pop:4933{4934if (!comp()->compileRelocatableCode())4935rotate(-1);4936return true;4937}4938case TR::java_lang_invoke_ILGenMacros_invokeExact:4939{4940if (!comp()->compileRelocatableCode())4941{4942TR_ResolvedMethod *invokeExactMacro = symRef->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod();4943TR::SymbolReference *invokeExact = comp()->getSymRefTab()->methodSymRefFromName(_methodSymbol, JSR292_MethodHandle, JSR292_invokeExact, JSR292_invokeExactSig, TR::MethodSymbol::ComputedVirtual);4944TR::SymbolReference *invokeExactWithSig = symRefWithArtificialSignature(invokeExact,4945"(.*).$",4946invokeExactMacro->signatureChars(), 1, // skip explicit MethodHandle argument -- invokeExact has it as a receiver4947invokeExactMacro->signatureChars());4948genILGenMacroInvokeExact(invokeExactWithSig);4949}4950return true;4951}4952case TR::java_lang_invoke_ILGenMacros_typeCheck:4953{4954if (!comp()->compileRelocatableCode())4955{4956TR::Node* expectedType = pop();4957TR::Node* handle = pop();4958genTreeTop(genHandleTypeCheck(handle, expectedType));4959}4960return true;4961}4962case TR::java_lang_invoke_ILGenMacros_arrayElements:4963{4964if (!comp()->compileRelocatableCode())4965{4966TR::Node *argPlaceholder = genNodeAndPopChildren(TR::icall, 3, symRef);4967TR::Node *array = argPlaceholder->getAndDecChild(0);4968int firstIndex = argPlaceholder->getAndDecChild(1)->getInt();4969int numElements = argPlaceholder->getAndDecChild(2)->getInt();49704971// The hard part here is computing the signature for the resulting placeholder!4972char *macroSignature = argPlaceholder->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod()->signatureChars();4973char *arrayElementType = macroSignature+2; // Skip parenthesis and bracket4974char *secondArgType = nextSignatureArgument(arrayElementType);4975int arrayElementTypeLength = secondArgType - arrayElementType;49764977char *expandedArgsSignature = (char*)comp()->trMemory()->allocateStackMemory(numElements * arrayElementTypeLength + 1);49784979TR::DataType arrayElementDataType = TR::NoType;4980TR::ILOpCodes convertOp = TR::BadILOp;4981switch (arrayElementType[0])4982{4983case 'Z':4984case 'B':4985arrayElementDataType = TR::Int8;4986convertOp = TR::b2i;4987break;4988case 'S':4989arrayElementDataType = TR::Int16;4990convertOp = TR::s2i;4991break;4992case 'C':4993arrayElementDataType = TR::Int16;4994convertOp = TR::su2i;4995break;4996case 'I':4997arrayElementDataType = TR::Int32;4998break;4999case 'J':5000arrayElementDataType = TR::Int64;5001break;5002case 'F':5003arrayElementDataType = TR::Float;5004break;5005case 'D':5006arrayElementDataType = TR::Double;5007break;5008case 'L':5009case '[':5010case 'Q':5011arrayElementDataType = TR::Address;5012break;5013default:5014TR_ASSERT(0, "Unknown array element type '%s'", arrayElementType);5015arrayElementDataType = TR::Address;5016break;5017}50185019char *cursor = expandedArgsSignature;5020cursor[0] = 0; // in case numElements==05021for (int32_t i = firstIndex; i < firstIndex+numElements; i++)5022{5023push(array);5024loadConstant(TR::iconst, i);5025loadArrayElement(arrayElementDataType);5026if (convertOp != TR::BadILOp)5027genUnary(convertOp);5028cursor += sprintf(cursor, "%.*s", arrayElementTypeLength, arrayElementType);5029}50305031// Create placeholder with signature that reflects the expansion of arguments.5032// Being a placeholder, its return type is still int.5033//5034TR::Node *placeholder = genNodeAndPopChildren(TR::icall, numElements, symRefWithArtificialSignature(placeholderWithDummySignature(),5035"(.?)I", expandedArgsSignature));50365037push(placeholder);5038}5039return true;5040}5041default:5042return false;5043}5044}50455046//----------------------------------------------5047// gen load5048//----------------------------------------------50495050void5051TR_J9ByteCodeIlGenerator::loadAuto(TR::DataType type, int32_t slot, bool isAdjunct)5052{5053if (_argPlaceholderSlot != -1 && _argPlaceholderSlot == slot)5054{5055genArgPlaceholderCall();5056return;5057}50585059TR::Node * load = TR::Node::createLoad(symRefTab()->findOrCreateAutoSymbol(_methodSymbol, slot, type, true, false, true, isAdjunct));5060// type may have been coerced5061type = load->getDataType();50625063bool isStatic = _methodSymbol->isStatic();5064if (slot == 0 && !isStatic && !_thisChanged)5065load->setIsNonNull(true);50665067push(load);5068}50695070/**5071* @brief Returns whether a field ref in the constant pool resolved5072*5073* Importantly, when this function returns false, a ResolveCHK is guarenteed to be needed.5074*5075* @param comp is a pointer the current compilation object5076* @param owningMethod is the method that owns the constant pool5077* @param cpIndex is the index into the constant pool of the field5078* @param isStore specifies whether the check is done for a store of the field5079* @return true when the constant pool entry for the field is resolved, false otherwise5080*/5081static bool5082isFieldResolved(TR::Compilation *comp, TR_ResolvedJ9Method * owningMethod, int32_t cpIndex, bool isStore)5083{5084uint32_t offset = 0;5085TR::DataType type = TR::NoType;5086bool isVolatile = true, isFinal = false, isPrivate = false, isUnresolvedInCP;5087return owningMethod->fieldAttributes(comp, cpIndex, &offset, &type, &isVolatile, &isFinal,5088&isPrivate, isStore, &isUnresolvedInCP, true /* needsAOTValidation */);5089}50905091void5092TR_J9ByteCodeIlGenerator::loadInstance(int32_t cpIndex)5093{5094if (_generateReadBarriersForFieldWatch && comp()->compileRelocatableCode())5095comp()->failCompilation<J9::AOTNoSupportForAOTFailure>("NO support for AOT in field watch");50965097TR_ResolvedJ9Method * owningMethod = static_cast<TR_ResolvedJ9Method*>(_methodSymbol->getResolvedMethod());5098if (TR::Compiler->om.areValueTypesEnabled() && owningMethod->isFieldQType(cpIndex))5099{5100if (!isFieldResolved(comp(), owningMethod, cpIndex, false))5101{5102abortForUnresolvedValueTypeOp("getfield", "field");5103}5104else if (owningMethod->isFieldFlattened(comp(), cpIndex, _methodSymbol->isStatic()))5105{5106return comp()->getOption(TR_UseFlattenedFieldRuntimeHelpers) ?5107loadFlattenableInstanceWithHelper(cpIndex) :5108loadFlattenableInstance(cpIndex);5109}5110}51115112TR::SymbolReference * symRef = symRefTab()->findOrCreateShadowSymbol(_methodSymbol, cpIndex, false);5113loadInstance(symRef);5114}51155116void5117TR_J9ByteCodeIlGenerator::loadInstance(TR::SymbolReference * symRef)5118{5119TR::Symbol * symbol = symRef->getSymbol();5120TR::DataType type = symbol->getDataType();51215122TR::Node * address = pop();51235124if (!symRef->isUnresolved() &&5125symRef->getSymbol()->isFinal())5126{5127TR::Node *constValue = loadConstantValueIfPossible(address, symRef->getOffset(), type, false);5128if (constValue)5129{5130return;5131}5132}51335134TR::Node * load, *dummyLoad;51355136TR::ILOpCodes op = _generateReadBarriersForFieldWatch ? comp()->il.opCodeForIndirectReadBarrier(type): comp()->il.opCodeForIndirectLoad(type);5137dummyLoad = load = TR::Node::createWithSymRef(op, 1, 1, address, symRef);51385139TR::Node * treeTopNode = 0;51405141if (symRef->isUnresolved())5142{5143if (!address->isNonNull())5144treeTopNode = genResolveAndNullCheck(load);5145else5146treeTopNode = genResolveCheck(load);5147}5148else if (!address->isNonNull())5149treeTopNode = genNullCheck(load);5150else if (symbol->isVolatile() || _generateReadBarriersForFieldWatch)5151treeTopNode = load;51525153if (treeTopNode)5154{5155handleSideEffect(treeTopNode);5156genTreeTop(treeTopNode);5157}51585159if (type == TR::Address)5160{51615162if (comp()->useCompressedPointers())5163{5164if (!symRefTab()->isFieldClassObject(symRef))5165{5166TR::Node *loadValue = load;5167if (loadValue->getOpCode().isCheck())5168loadValue = loadValue->getFirstChild();5169// returns non-null if the compressedRefs anchor is going to5170// be part of the subtrees (for now, it is a treetop)5171//5172TR::Node *newLoad = genCompressedRefs(loadValue);5173if (newLoad)5174load = newLoad;5175}5176}5177}51785179static char *disableFinalFieldFoldingInILGen = feGetEnv("TR_DisableFinalFieldFoldingInILGen");5180static char *disableInstanceFinalFieldFoldingInILGen = feGetEnv("TR_DisableInstanceFinalFieldFoldingInILGen");5181if (!disableFinalFieldFoldingInILGen &&5182!disableInstanceFinalFieldFoldingInILGen &&5183address->getOpCode().hasSymbolReference() &&5184address->getSymbolReference()->hasKnownObjectIndex() &&5185address->isNonNull())5186{5187TR::Node* nodeToRemove = NULL;5188if (TR::TransformUtil::transformIndirectLoadChain(comp(), dummyLoad, address, address->getSymbolReference()->getKnownObjectIndex(), &nodeToRemove) && nodeToRemove)5189{5190nodeToRemove->recursivelyDecReferenceCount();5191}5192}51935194push(dummyLoad);5195}51965197void5198TR_J9ByteCodeIlGenerator::loadFlattenableInstanceWithHelper(int32_t cpIndex)5199{5200TR::Node * address = pop();5201if (!address->isNonNull())5202{5203auto* nullchk = TR::Node::create(TR::PassThrough, 1, address);5204nullchk = genNullCheck(nullchk);5205genTreeTop(nullchk);5206}5207auto* j9ResolvedMethod = static_cast<TR_ResolvedJ9Method *>(_methodSymbol->getResolvedMethod());5208auto* ramFieldRef = reinterpret_cast<J9RAMFieldRef*>(j9ResolvedMethod->cp()) + cpIndex;5209auto* ramFieldRefNode = TR::Node::aconst(reinterpret_cast<uintptr_t>(ramFieldRef));5210auto* receiverNode = address;5211auto* helperCallNode = TR::Node::createWithSymRef(TR::acall, 2, 2, receiverNode, ramFieldRefNode, comp()->getSymRefTab()->findOrCreateGetFlattenableFieldSymbolRef());5212handleSideEffect(helperCallNode);5213genTreeTop(helperCallNode);5214push(helperCallNode);5215}52165217static char * getTopLevelPrefixForFlattenedFields(TR_ResolvedJ9Method *owningMethod, int32_t cpIndex, int32_t &prefixLen, TR::Region ®ion)5218{5219int32_t len;5220const char * fieldNameChars = owningMethod->fieldNameChars(cpIndex, len);5221prefixLen = len + 1; // for '.'52225223char * newName = new (region) char[len+2];5224strncpy(newName, fieldNameChars, len);52255226newName[len] = '.';5227newName[len+1] = '\0';5228return newName;5229}52305231void5232TR_J9ByteCodeIlGenerator::loadFlattenableInstance(int32_t cpIndex)5233{5234/* An example on what the tree with flattened fields looks like5235*5236* value NestedA {5237* int x;5238* int y;5239* }5240* value NestedB {5241* NestedA a;5242* NestedA b;5243* }5244* value ContainerC {5245* NestedB c;5246* NestedB d;5247* }5248*5249* method="ContainerC.getc()QNestedB;"5250*5251* /--- trees inserted ------------------------5252* n10n ( 0) treetop5253* n9n ( 1) newvalue jitNewValue[#100 helper Method] [flags 0x400 0x0 ] (Identityless sharedMemory )5254* n4n ( 1) loadaddr NestedB[#367 Static] [flags 0x18307 0x0 ]5255* n5n ( 1) iloadi ContainerC.c.a.x I[#368 final ContainerC.c.a.x I +4] [flags 0x20603 0x200 ]5256* n3n ( 4) aload <'this' parm LContainerC;>[#366 Parm] [flags 0x40000107 0x0 ] (X!=0 sharedMemory )5257* n6n ( 1) iloadi ContainerC.c.a.y I[#369 final ContainerC.c.a.y I +8] [flags 0x20603 0x200 ]5258* n3n ( 4) ==>aload (X!=0 sharedMemory )5259* n7n ( 1) iloadi ContainerC.c.b.x I[#370 final ContainerC.c.b.x I +12] [flags 0x20603 0x200 ]5260* n3n ( 4) ==>aload (X!=0 sharedMemory )5261* n8n ( 1) iloadi ContainerC.c.b.y I[#371 final ContainerC.c.b.y I +16] [flags 0x20603 0x200 ]5262* n3n ( 4) ==>aload (X!=0 sharedMemory )5263* /--- stack after ------------------------5264* @0 n9n ( 1) ==>newvalue (Identityless sharedMemory )5265* ============================================================5266*/5267TR_ResolvedJ9Method * owningMethod = static_cast<TR_ResolvedJ9Method*>(_methodSymbol->getResolvedMethod());52685269int len;5270const char * fieldClassChars = owningMethod->fieldSignatureChars(cpIndex, len);5271TR_OpaqueClassBlock * fieldClass = fej9()->getClassFromSignature(fieldClassChars, len, owningMethod);52725273int32_t prefixLen = 0;5274char * fieldNamePrefix = getTopLevelPrefixForFlattenedFields(owningMethod, cpIndex, prefixLen, comp()->trMemory()->currentStackRegion());52755276TR_OpaqueClassBlock * containingClass = owningMethod->definingClassFromCPFieldRef(comp(), cpIndex, _methodSymbol->isStatic());5277const TR::TypeLayout * containingClassLayout = comp()->typeLayout(containingClass);5278size_t fieldCount = containingClassLayout->count();5279int flattenedFieldCount = 0;52805281TR::Node * address = pop();52825283if (!address->isNonNull())5284{5285TR::Node * passThruNode = TR::Node::create(TR::PassThrough, 1, address);5286genTreeTop(genNullCheck(passThruNode));5287}52885289loadClassObject(fieldClass);52905291for (size_t idx = 0; idx < fieldCount; idx++)5292{5293const TR::TypeLayoutEntry &fieldEntry = containingClassLayout->entry(idx);52945295if (!strncmp(fieldNamePrefix, fieldEntry._fieldname, prefixLen))5296{5297auto * fieldSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(containingClass,5298fieldEntry._datatype,5299fieldEntry._offset,5300fieldEntry._isVolatile,5301fieldEntry._isPrivate,5302fieldEntry._isFinal,5303fieldEntry._fieldname,5304fieldEntry._typeSignature);53055306if (comp()->getOption(TR_TraceILGen))5307{5308traceMsg(comp(), "Load flattened field %s\n - field[%d] name %s type %d offset %d\n",5309comp()->getDebug()->getName(fieldSymRef), idx, fieldEntry._fieldname,5310fieldEntry._datatype.getDataType(), fieldEntry._offset);5311}53125313push(address);5314loadInstance(fieldSymRef);53155316flattenedFieldCount++;5317}5318}53195320TR::Node * newValueNode = genNodeAndPopChildren(TR::newvalue, flattenedFieldCount + 1, symRefTab()->findOrCreateNewValueSymbolRef(_methodSymbol));5321newValueNode->setIdentityless(true);5322genTreeTop(newValueNode);5323push(newValueNode);5324genFlush(0);5325return;5326}53275328void5329TR_J9ByteCodeIlGenerator::loadStatic(int32_t cpIndex)5330{5331if (_generateReadBarriersForFieldWatch && comp()->compileRelocatableCode())5332comp()->failCompilation<J9::AOTNoSupportForAOTFailure>("NO support for AOT in field watch");53335334_staticFieldReferenceEncountered = true;5335TR::SymbolReference * symRef = symRefTab()->findOrCreateStaticSymbol(_methodSymbol, cpIndex, false);5336if (comp()->getOption(TR_TraceILGen))5337traceMsg(comp(), "load static symref %d created with knownObjectIndex %d", symRef->getReferenceNumber(), symRef->getKnownObjectIndex());5338TR::StaticSymbol * symbol = symRef->getSymbol()->castToStaticSymbol();5339TR_ASSERT(symbol, "Didn't geta static symbol.");53405341TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp()->fej9());53425343if (!comp()->isDLT())5344{5345TR::Symbol::RecognizedField recognizedField = symbol->getRecognizedField();5346switch (recognizedField)5347{5348case TR::Symbol::Java_math_BigInteger_useLongRepresentation:5349{5350// always evaluate to be true5351loadConstant(TR::iconst, 1);5352return;5353}5354case TR::Symbol::Com_ibm_jit_JITHelpers_IS_32_BIT:5355{5356int32_t constValue = comp()->target().is64Bit() ? 0 : 1;5357loadConstant(TR::iconst, constValue);5358return;5359}5360case TR::Symbol::Com_ibm_jit_JITHelpers_J9OBJECT_J9CLASS_OFFSET:5361{5362loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfJ9ObjectJ9Class());5363return;5364}5365case TR::Symbol::Com_ibm_jit_JITHelpers_J9OBJECT_FLAGS_MASK32:5366{5367loadConstant(TR::iconst, (int32_t)fej9->getJ9ObjectFlagsMask32());5368return;5369}5370case TR::Symbol::Com_ibm_jit_JITHelpers_J9OBJECT_FLAGS_MASK64:5371{5372loadConstant(TR::iconst, (int32_t)fej9->getJ9ObjectFlagsMask64());5373return;5374}5375case TR::Symbol::Com_ibm_jit_JITHelpers_JLTHREAD_J9THREAD_OFFSET:5376{5377loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfJLThreadJ9Thread());5378return;5379}5380case TR::Symbol::Com_ibm_jit_JITHelpers_J9THREAD_J9VM_OFFSET:5381{5382loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfJ9ThreadJ9VM());5383return;5384}5385case TR::Symbol::Com_ibm_jit_JITHelpers_J9ROMARRAYCLASS_ARRAYSHAPE_OFFSET:5386{5387loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfJ9ROMArrayClassArrayShape());5388return;5389}5390case TR::Symbol::Com_ibm_jit_JITHelpers_J9CLASS_BACKFILL_OFFSET_OFFSET:5391{5392loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfBackfillOffsetField());5393return;5394}5395case TR::Symbol::Com_ibm_jit_JITHelpers_ARRAYSHAPE_ELEMENTCOUNT_MASK:5396{5397loadConstant(TR::iconst, 65535);5398return;5399}5400case TR::Symbol::Com_ibm_jit_JITHelpers_J9CONTIGUOUSARRAY_HEADER_SIZE:5401{5402loadConstant(TR::iconst, (int32_t)TR::Compiler->om.contiguousArrayHeaderSizeInBytes());5403return;5404}5405case TR::Symbol::Com_ibm_jit_JITHelpers_J9DISCONTIGUOUSARRAY_HEADER_SIZE:5406{5407loadConstant(TR::iconst, (int32_t)TR::Compiler->om.discontiguousArrayHeaderSizeInBytes());5408return;5409}5410case TR::Symbol::Com_ibm_jit_JITHelpers_J9OBJECT_CONTIGUOUS_LENGTH_OFFSET:5411{5412loadConstant(TR::iconst, (int32_t)fej9->getJ9ObjectContiguousLength());5413return;5414}5415case TR::Symbol::Com_ibm_jit_JITHelpers_J9OBJECT_DISCONTIGUOUS_LENGTH_OFFSET:5416{5417loadConstant(TR::iconst, (int32_t)fej9->getJ9ObjectDiscontiguousLength());5418return;5419}5420case TR::Symbol::Com_ibm_jit_JITHelpers_JLOBJECT_ARRAY_BASE_OFFSET:5421{5422loadConstant(TR::iconst, 8);5423return;5424}5425case TR::Symbol::Com_ibm_jit_JITHelpers_J9CLASS_J9ROMCLASS_OFFSET:5426{5427loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfClassRomPtrField());5428return;5429}5430case TR::Symbol::Com_ibm_jit_JITHelpers_J9JAVAVM_IDENTITY_HASH_DATA_OFFSET:5431{5432loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfJavaVMIdentityHashData());5433return;5434}5435case TR::Symbol::Com_ibm_jit_JITHelpers_J9IDENTITYHASHDATA_HASH_DATA1_OFFSET:5436{5437loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfJ9IdentityHashData1());5438return;5439}5440case TR::Symbol::Com_ibm_jit_JITHelpers_J9IDENTITYHASHDATA_HASH_DATA2_OFFSET:5441{5442loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfJ9IdentityHashData2());5443return;5444}5445case TR::Symbol::Com_ibm_jit_JITHelpers_J9IDENTITYHASHDATA_HASH_DATA3_OFFSET:5446{5447loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfJ9IdentityHashData3());5448return;5449}5450case TR::Symbol::Com_ibm_jit_JITHelpers_J9IDENTITYHASHDATA_HASH_SALT_TABLE_OFFSET:5451{5452loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfJ9IdentityHashDataHashSaltTable());5453return;5454}5455case TR::Symbol::Com_ibm_jit_JITHelpers_J9_IDENTITY_HASH_SALT_POLICY_STANDARD:5456{5457loadConstant(TR::iconst, (int32_t)fej9->getJ9IdentityHashSaltPolicyStandard());5458return;5459}5460case TR::Symbol::Com_ibm_jit_JITHelpers_J9_IDENTITY_HASH_SALT_POLICY_REGION:5461{5462loadConstant(TR::iconst, (int32_t)fej9->getJ9IdentityHashSaltPolicyRegion());5463return;5464}5465case TR::Symbol::Com_ibm_jit_JITHelpers_J9_IDENTITY_HASH_SALT_POLICY_NONE:5466{5467loadConstant(TR::iconst, (int32_t)fej9->getJ9IdentityHashSaltPolicyNone());5468return;5469}5470case TR::Symbol::Com_ibm_jit_JITHelpers_IDENTITY_HASH_SALT_POLICY:5471{5472loadConstant(TR::iconst, (int32_t)fej9->getIdentityHashSaltPolicy());5473return;5474}5475case TR::Symbol::Com_ibm_oti_vm_VM_J9CLASS_CLASS_FLAGS_OFFSET:5476{5477loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfClassFlags());5478return;5479}5480case TR::Symbol::Com_ibm_oti_vm_VM_J9CLASS_INITIALIZE_STATUS_OFFSET:5481{54825483loadConstant(TR::iconst, (int32_t)fej9->getOffsetOfClassInitializeStatus());5484return;5485}5486case TR::Symbol::Com_ibm_oti_vm_VM_J9_JAVA_CLASS_RAM_SHAPE_SHIFT:5487{5488loadConstant(TR::iconst, (int32_t)fej9->getJ9JavaClassRamShapeShift());5489return;5490}5491case TR::Symbol::Com_ibm_oti_vm_VM_OBJECT_HEADER_SHAPE_MASK:5492{5493loadConstant(TR::iconst, (int32_t)fej9->getObjectHeaderShapeMask());5494return;5495}5496case TR::Symbol::Com_ibm_oti_vm_VM_ADDRESS_SIZE:5497{5498loadConstant(TR::iconst, (int32_t)sizeof(uintptr_t));5499return;5500}5501default:5502break;5503}5504}55055506TR::DataType type = symbol->getDataType();5507bool isResolved = !symRef->isUnresolved();5508TR_OpaqueClassBlock * classOfStatic = isResolved ? _method->classOfStatic(cpIndex) : 0;5509if (classOfStatic == NULL)5510{5511int len = 0;5512char * classNameOfFieldOrStatic = NULL;5513classNameOfFieldOrStatic = symRef->getOwningMethod(comp())->classNameOfFieldOrStatic(symRef->getCPIndex(), len);5514if (classNameOfFieldOrStatic)5515{5516classNameOfFieldOrStatic = TR::Compiler->cls.classNameToSignature(classNameOfFieldOrStatic, len, comp());5517TR_OpaqueClassBlock * curClass = fej9->getClassFromSignature(classNameOfFieldOrStatic, len, symRef->getOwningMethod(comp()));5518TR_OpaqueClassBlock * owningClass = comp()->getJittedMethodSymbol()->getResolvedMethod()->containingClass();5519if (owningClass == curClass)5520classOfStatic = curClass;5521}5522}552355245525bool isClassInitialized = false;5526TR_PersistentClassInfo * classInfo = _noLookahead ? 0 :5527comp()->getPersistentInfo()->getPersistentCHTable()->findClassInfoAfterLocking(classOfStatic, comp());5528if (classInfo && classInfo->isInitialized())5529isClassInitialized = true;55305531/*5532if (classOfStatic)5533{5534char *name; int32_t len;5535name = comp()->fej9->getClassNameChars(classOfStatic, len);5536printf("class name %s class init %d class %p classInfo %p no %d hotness %d\n", name, isClassInitialized, classOfStatic, classInfo, _noLookahead, comp()->getMethodHotness()); fflush(stdout);5537}5538*/55395540bool canOptimizeFinalStatic = false;5541if (isResolved && symbol->isFinal() && !symRef->isUnresolved() &&5542classOfStatic != comp()->getSystemClassPointer() &&5543isClassInitialized)5544{5545//if (type == TR::Address)5546{55475548// todo: figure out why classInfo would be NULL here?5549if (!classInfo->getFieldInfo())5550performClassLookahead(classInfo);5551}55525553if (classInfo->getFieldInfo() && !classInfo->cannotTrustStaticFinal())5554canOptimizeFinalStatic = true;5555}55565557TR::VMAccessCriticalSection loadStaticCriticalSection(fej9,5558TR::VMAccessCriticalSection::tryToAcquireVMAccess,5559comp());55605561TR::Node * load = NULL;55625563if (canOptimizeFinalStatic &&5564loadStaticCriticalSection.hasVMAccess())5565{5566void * p = symbol->getStaticAddress();55675568switch (type)5569{5570case TR::Address:5571if ((void *)comp()->fej9()->getStaticReferenceFieldAtAddress((uintptr_t)p) == 0)5572{5573loadConstant(TR::aconst, 0);5574break;5575}5576else5577{5578// the address isn't constant, because a GC could move it, however is it nonnull5579//5580load = TR::Node::createLoad(symRef);5581load->setIsNonNull(true);5582push(load);5583break;5584}5585case TR::Double: loadConstant(TR::dconst, *(double *) p); break;5586case TR::Int64: loadConstant(TR::lconst, *(int64_t *)p); break;5587case TR::Float: loadConstant(TR::fconst, *(float *) p); break;5588case TR::Int32:5589default: loadConstant(TR::iconst, *(int32_t *)p); break;5590}5591}5592else if (symbol->isVolatile() && type == TR::Int64 && isResolved && comp()->target().is32Bit() &&5593!comp()->cg()->getSupportsInlinedAtomicLongVolatiles() && 0)5594{5595TR::SymbolReference * volatileLongSymRef =5596comp()->getSymRefTab()->findOrCreateRuntimeHelper(TR_volatileReadLong, false, false, true);5597TR::Node * statics = TR::Node::createWithSymRef(TR::loadaddr, 0, symRef);5598TR::Node * call = TR::Node::createWithSymRef(TR::lcall, 1, 1, statics, volatileLongSymRef);55995600handleSideEffect(call);56015602genTreeTop(call);5603push(call);5604}5605else5606{5607if (_generateReadBarriersForFieldWatch)5608{5609void * staticClass = method()->classOfStatic(cpIndex);5610loadSymbol(TR::loadaddr, symRefTab()->findOrCreateClassSymbol(_methodSymbol, cpIndex, staticClass, true /* cpIndexOfStatic */));5611load = TR::Node::createWithSymRef(comp()->il.opCodeForDirectReadBarrier(type), 1, pop(), 0, symRef);5612}5613else5614load = TR::Node::createWithSymRef(comp()->il.opCodeForDirectLoad(type), 0, symRef);56155616TR::Node * treeTopNode = 0;5617if (symRef->isUnresolved())5618treeTopNode = genResolveCheck(load);5619else if (symbol->isVolatile() || _generateReadBarriersForFieldWatch)5620treeTopNode = load;56215622if (treeTopNode)5623{5624handleSideEffect(treeTopNode);5625genTreeTop(treeTopNode);5626}56275628push(load);5629}56305631static char *disableFinalFieldFoldingInILGen = feGetEnv("TR_DisableFinalFieldFoldingInILGen");5632static char *disableStaticFinalFieldFoldingInILGen = feGetEnv("TR_DisableStaticFinalFieldFoldingInILGen");5633if (load &&5634!disableFinalFieldFoldingInILGen &&5635!disableStaticFinalFieldFoldingInILGen &&5636symbol->isFinal() &&5637TR::TransformUtil::canFoldStaticFinalField(comp(), load) == TR_yes)5638{5639TR::TransformUtil::foldReliableStaticFinalField(comp(), load);5640}56415642}56435644TR::Node *5645TR_J9ByteCodeIlGenerator::loadSymbol(TR::ILOpCodes loadop, TR::SymbolReference * symRef)5646{5647TR::Node * node = TR::Node::createWithSymRef(loadop, 0, symRef);56485649if (symRef->isUnresolved())5650{5651TR::Node * treeTopNode = genResolveCheck(node);5652handleSideEffect(treeTopNode);5653genTreeTop(treeTopNode);5654}56555656push(node);5657return node;5658}56595660void5661TR_J9ByteCodeIlGenerator::loadClassObject(int32_t cpIndex)5662{5663void * classObject = method()->getClassFromConstantPool(comp(), cpIndex);5664loadSymbol(TR::loadaddr, symRefTab()->findOrCreateClassSymbol(_methodSymbol, cpIndex, classObject));5665}56665667/**5668* Push a loadaddr of the class for cpIndex without emitting ResolveCHK.5669*5670* This is needed for checkcast and instanceof bytecode instructions, which are5671* required not to resolve classes when the tested object is null, so they5672* can't run ResolveCHK unconditionally.5673*5674* @param cpIndex The index of the constant pool entry that specifies the class5675* @param aotInhibit The JIT option to disallow using the resolved class for AOT5676* @return The symbol reference for the class5677*5678* @see genCheckCast(int32_t)5679* @see genInstanceof(int32_t)5680*/5681TR::SymbolReference *5682TR_J9ByteCodeIlGenerator::loadClassObjectForTypeTest(int32_t cpIndex, TR_CompilationOptions aotInhibit)5683{5684bool aotOK = !comp()->compileRelocatableCode() || !comp()->getOption(aotInhibit);5685void *classObject = method()->getClassFromConstantPool(comp(), cpIndex, aotOK);5686TR::SymbolReference *symRef = symRefTab()->findOrCreateClassSymbol(_methodSymbol, cpIndex, classObject);5687TR::Node *node = TR::Node::createWithSymRef(TR::loadaddr, 0, symRef);5688if (symRef->isUnresolved())5689{5690// We still need to anchor from the stack *as though* we were emitting5691// the ResolveCHK, since the type test will expand to include one later.5692TR::Node *dummyResolveCheck = genResolveCheck(node);5693handleSideEffect(dummyResolveCheck);5694node->decReferenceCount();5695}5696push(node);5697return symRef;5698}56995700void5701TR_J9ByteCodeIlGenerator::loadClassObject(TR_OpaqueClassBlock *opaqueClass)5702{5703loadSymbol(TR::loadaddr, symRefTab()->findOrCreateClassSymbol(_methodSymbol, 0, opaqueClass));5704}57055706void5707TR_J9ByteCodeIlGenerator::loadClassObjectAndIndirect(int32_t cpIndex)5708{5709void * classObject = method()->getClassFromConstantPool(comp(), cpIndex);5710loadSymbol(TR::loadaddr, symRefTab()->findOrCreateClassSymbol(_methodSymbol, cpIndex, classObject));5711TR::Node* node = pop();5712node = TR::Node::createWithSymRef(TR::aloadi, 1, 1, node, symRefTab()->findOrCreateJavaLangClassFromClassSymbolRef());5713push(node);5714}571557165717void5718TR_J9ByteCodeIlGenerator::loadConstant(TR::ILOpCodes loadop, int32_t constant)5719{5720push(TR::Node::create(loadop, 0, constant));5721}57225723void5724TR_J9ByteCodeIlGenerator::loadConstant(TR::ILOpCodes loadop, int64_t constant)5725{5726TR::Node * node = TR::Node::create(loadop, 0);5727node->setConstValue(constant);5728push(node);5729}57305731void5732TR_J9ByteCodeIlGenerator::loadConstant(TR::ILOpCodes loadop, float constant)5733{5734TR::Node * node = TR::Node::create(loadop, 0);5735node->setFloat(constant);5736push(node);5737}57385739void5740TR_J9ByteCodeIlGenerator::loadConstant(TR::ILOpCodes loadop, double constant)5741{5742TR::Node * node = TR::Node::create(loadop, 0);5743node->setDouble(constant);5744push(node);5745}57465747void5748TR_J9ByteCodeIlGenerator::loadConstant(TR::ILOpCodes loadop, void * constant)5749{5750TR::Node * node = TR::Node::create(loadop, 0);5751node->setAddress((uintptr_t)constant);5752push(node);5753}57545755void5756TR_J9ByteCodeIlGenerator::loadFromCP(TR::DataType type, int32_t cpIndex)5757{5758static char *floatInCP = feGetEnv("TR_FloatInCP");5759if (type == TR::NoType)5760type = method()->getLDCType(cpIndex);5761switch (type)5762{5763case TR::Int32: loadConstant(TR::iconst, (int32_t)method()->intConstant(cpIndex)); break;5764case TR::Int64: loadConstant(TR::lconst, (int64_t)method()->longConstant(cpIndex)); break;5765case TR::Float:5766if (!floatInCP)5767loadConstant(TR::fconst, * method()->floatConstant(cpIndex));5768else5769loadSymbol(TR::fload, symRefTab()->findOrCreateFloatSymbol(_methodSymbol, cpIndex));5770break;5771case TR::Double:5772if (!floatInCP)5773loadConstant(TR::dconst, *(double*)method()->doubleConstant(cpIndex, trMemory()));5774else5775loadSymbol(TR::dload, symRefTab()->findOrCreateDoubleSymbol(_methodSymbol, cpIndex));5776break;5777case TR::Address:5778if (method()->isConstantDynamic(cpIndex))5779{5780if (comp()->compileRelocatableCode())5781{5782if (comp()->getOption(TR_TraceILGen))5783traceMsg(comp(), " Constant Dynamic not supported in AOT.\n");5784comp()->failCompilation<J9::AOTHasConstantDynamic>("Constant Dynamic not supported in AOT.");5785}57865787bool isCondyUnresolved = _methodSymbol->getResolvedMethod()->isUnresolvedConstantDynamic(cpIndex);5788J9UTF8 *returnTypeUtf8 = (J9UTF8 *)_methodSymbol->getResolvedMethod()->getConstantDynamicTypeFromCP(cpIndex);5789int returnTypeUtf8Length = J9UTF8_LENGTH(returnTypeUtf8);5790char* returnTypeUtf8Data = (char *)J9UTF8_DATA(returnTypeUtf8);5791bool isCondyPrimitive = (1 == returnTypeUtf8Length);57925793// Use aconst for null object5794if (!isCondyPrimitive && !isCondyUnresolved)5795{5796TR::VMAccessCriticalSection condyCriticalSection(comp()->fej9());5797uintptr_t obj = 0;5798uintptr_t* objLocation = (uintptr_t*)_methodSymbol->getResolvedMethod()->dynamicConstant(cpIndex, &obj);5799if (obj == 0)5800{5801loadConstant(TR::aconst, (void *)0);5802return;5803}5804}58055806char* symbolTypeSig = NULL;5807int32_t symbolTypeSigLength = 0;5808// For non-primitive condy, resolved or not, we create a static symbol,5809// store the class info in the symbol so it may be retrieved by optimizer later via5810// getTypeSignature.5811if (!isCondyPrimitive)5812{5813symbolTypeSig = (char*)comp()->trMemory()->allocateMemory(returnTypeUtf8Length, heapAlloc);5814symbolTypeSigLength = returnTypeUtf8Length;5815memcpy(symbolTypeSig, returnTypeUtf8Data, symbolTypeSigLength);5816}58175818TR_OpaqueClassBlock * typeClassBlock = NULL;5819int32_t valueOffset = 0;58205821// If condy is primitive type and resolved, load the primitive constant;5822// Otherwise, load using a CP symbol (for resolved and unresolved object type),5823// and generate subsequent loadi for the unresolved primitive 'value' field if needed (because5824// for unresolved primitive the resolve helper only returns an autobox'd object).5825if (isCondyPrimitive)5826{5827char *autoboxClassSig = NULL;5828int32_t autoboxClassSigLength = 0;5829switch (returnTypeUtf8Data[0])5830{5831case 'I':5832autoboxClassSig = "Ljava/lang/Integer;";5833autoboxClassSigLength = 19;5834typeClassBlock = comp()->fej9()->getClassFromSignature(autoboxClassSig, autoboxClassSigLength, method());5835valueOffset = comp()->fej9()->getObjectHeaderSizeInBytes()5836+ comp()->fej9()->getInstanceFieldOffset(typeClassBlock, "value", 5, "I", 1);5837break;5838case 'J':5839autoboxClassSig = "Ljava/lang/Long;";5840autoboxClassSigLength = 16;5841typeClassBlock = comp()->fej9()->getClassFromSignature(autoboxClassSig, autoboxClassSigLength, method());5842valueOffset = comp()->fej9()->getObjectHeaderSizeInBytes()5843+ comp()->fej9()->getInstanceFieldOffset(typeClassBlock, "value", 5, "J", 1);5844break;5845case 'F':5846autoboxClassSig = "Ljava/lang/Float;";5847autoboxClassSigLength = 17;5848typeClassBlock = comp()->fej9()->getClassFromSignature(autoboxClassSig, autoboxClassSigLength, method());5849valueOffset = comp()->fej9()->getObjectHeaderSizeInBytes()5850+ comp()->fej9()->getInstanceFieldOffset(typeClassBlock, "value", 5, "F", 1);5851break;5852case 'D':5853autoboxClassSig = "Ljava/lang/Double;";5854autoboxClassSigLength = 18;5855typeClassBlock = comp()->fej9()->getClassFromSignature(autoboxClassSig, autoboxClassSigLength, method());5856valueOffset = comp()->fej9()->getObjectHeaderSizeInBytes()5857+ comp()->fej9()->getInstanceFieldOffset(typeClassBlock, "value", 5, "D", 1);5858break;5859case 'B':5860autoboxClassSig = "Ljava/lang/Byte;";5861autoboxClassSigLength = 16;5862typeClassBlock = comp()->fej9()->getClassFromSignature(autoboxClassSig, autoboxClassSigLength, method());5863valueOffset = comp()->fej9()->getObjectHeaderSizeInBytes()5864+ comp()->fej9()->getInstanceFieldOffset(typeClassBlock, "value", 5, "B", 1);5865break;5866case 'C':5867autoboxClassSig = "Ljava/lang/Character;";5868autoboxClassSigLength = 21;5869typeClassBlock = comp()->fej9()->getClassFromSignature(autoboxClassSig, autoboxClassSigLength, method());5870valueOffset = comp()->fej9()->getObjectHeaderSizeInBytes()5871+ comp()->fej9()->getInstanceFieldOffset(typeClassBlock, "value", 5, "C", 1);5872break;5873case 'S':5874autoboxClassSig = "Ljava/lang/Short;";5875autoboxClassSigLength = 17;5876typeClassBlock = comp()->fej9()->getClassFromSignature(autoboxClassSig, autoboxClassSigLength, method());5877valueOffset = comp()->fej9()->getObjectHeaderSizeInBytes()5878+ comp()->fej9()->getInstanceFieldOffset(typeClassBlock, "value", 5, "S", 1);5879break;5880case 'Z':5881autoboxClassSig = "Ljava/lang/Boolean;";5882autoboxClassSigLength = 19;5883typeClassBlock = comp()->fej9()->getClassFromSignature(autoboxClassSig, autoboxClassSigLength, method());5884valueOffset = comp()->fej9()->getObjectHeaderSizeInBytes()5885+ comp()->fej9()->getInstanceFieldOffset(typeClassBlock, "value", 5, "Z", 1);5886break;5887default:5888TR_ASSERT_FATAL(false, "Unrecognized primitive constant dynamic type signature");5889break;5890}5891// Generate constant for resolved primitive condy.5892if(!isCondyUnresolved)5893{5894TR::VMAccessCriticalSection primitiveCondyCriticalSection(comp()->fej9(),5895TR::VMAccessCriticalSection::tryToAcquireVMAccess,5896comp());5897if (primitiveCondyCriticalSection.hasVMAccess())5898{5899uintptr_t obj = 0;5900uintptr_t* objLocation = (uintptr_t*)_methodSymbol->getResolvedMethod()->dynamicConstant(cpIndex, &obj);5901TR_ASSERT(obj, "Resolved primitive Constant Dynamic-type CP entry %d must have autobox object", cpIndex);5902switch (returnTypeUtf8Data[0])5903{5904case 'I':5905case 'Z':5906case 'C':5907case 'S':5908case 'B':5909loadConstant(TR::iconst, *(int32_t*)(obj+valueOffset));5910break;5911case 'J':5912loadConstant(TR::lconst, *(int64_t*)(obj+valueOffset));5913break;5914case 'F':5915loadConstant(TR::fconst, *(float*)(obj+valueOffset));5916break;5917case 'D':5918loadConstant(TR::dconst, *(double*)(obj+valueOffset));5919break;5920default:5921TR_ASSERT_FATAL(false, "Unrecognized primitive constant dynamic type signature");5922break;5923}5924return;5925}5926}5927// If the primitive condy is unresolved, OR resolved but we fail to acquire VM access,5928// proceed to generate the loads. Store the type signature info in the symbol so it may be5929// retrieved by optimizer later.5930symbolTypeSig = (char*)comp()->trMemory()->allocateMemory(autoboxClassSigLength, heapAlloc);5931symbolTypeSigLength = autoboxClassSigLength;5932memcpy(symbolTypeSig, autoboxClassSig, symbolTypeSigLength);5933}5934TR::Node * loadObjNode = loadSymbol(TR::aload, symRefTab()->findOrCreateConstantDynamicSymbol(_methodSymbol, cpIndex,5935symbolTypeSig, symbolTypeSigLength, isCondyPrimitive));5936// Condy is primitive type, emit indirect load of the value field from the autobox object.5937if (isCondyPrimitive)5938{5939char *recogFieldName = NULL;5940TR::Symbol::RecognizedField valueRecogField= TR::Symbol::UnknownField;5941TR::DataType dt = TR::NoType;5942switch (returnTypeUtf8Data[0])5943{5944case 'I':5945recogFieldName = "java/lang/Integer.value I";5946valueRecogField = TR::Symbol::Java_lang_Integer_value;5947dt = TR::Int32;5948break;5949case 'J':5950recogFieldName = "java/lang/Long.value J";5951valueRecogField = TR::Symbol::Java_lang_Long_value;5952dt = TR::Int64;5953break;5954case 'F':5955recogFieldName = "java/lang/Float.value F";5956valueRecogField = TR::Symbol::Java_lang_Float_value;5957dt = TR::Float;5958break;5959case 'D':5960recogFieldName = "java/lang/Double.value D";5961valueRecogField = TR::Symbol::Java_lang_Double_value;5962dt = TR::Double;5963break;5964case 'B':5965recogFieldName = "java/lang/Byte.value B";5966valueRecogField = TR::Symbol::Java_lang_Byte_value;5967dt = TR::Int8;5968break;5969case 'C':5970recogFieldName = "java/lang/Character.value C";5971valueRecogField = TR::Symbol::Java_lang_Character_value;5972dt = TR::Int16;5973break;5974case 'S':5975recogFieldName = "java/lang/Short.value S";5976valueRecogField = TR::Symbol::Java_lang_Short_value;5977dt = TR::Int16;5978break;5979case 'Z':5980recogFieldName = "java/lang/Boolean.value Z";5981valueRecogField = TR::Symbol::Java_lang_Boolean_value;5982dt = TR::Int32;5983break;5984default:5985TR_ASSERT_FATAL(false, "Unrecognized primitive constant dynamic type signature");5986break;5987}5988TR::SymbolReference *valueSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(_methodSymbol,5989valueRecogField, dt, valueOffset, false, true, true, recogFieldName);5990TR::Node *primitiveValueNode = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectLoad(dt),59911, 1, pop(), valueSymRef);5992primitiveValueNode->copyByteCodeInfo(loadObjNode);5993push(primitiveValueNode);5994}5995}5996else if (method()->isClassConstant(cpIndex))5997{5998loadClassObjectAndIndirect(cpIndex);5999}6000else if (method()->isStringConstant(cpIndex))6001{6002loadSymbol(TR::aload, symRefTab()->findOrCreateStringSymbol(_methodSymbol, cpIndex));6003}6004else if (method()->isMethodHandleConstant(cpIndex))6005{6006if (comp()->compileRelocatableCode())6007{6008if (comp()->getOption(TR_TraceILGen))6009traceMsg(comp(), " Method Handle Constant not supported in AOT.\n");6010comp()->failCompilation<J9::AOTHasMethodHandleConstant>("Method Handle Constant not supported in AOT.");6011}6012loadSymbol(TR::aload, symRefTab()->findOrCreateMethodHandleSymbol(_methodSymbol, cpIndex));6013}6014else6015{6016TR_ASSERT(method()->isMethodTypeConstant(cpIndex), "Address-type CP entry %d must be class, string, methodHandle, or methodType", cpIndex);6017if (comp()->compileRelocatableCode())6018{6019if (comp()->getOption(TR_TraceILGen))6020traceMsg(comp(), " Method Type Constant not supported in AOT.\n");6021comp()->failCompilation<J9::AOTHasMethodTypeConstant>("Method Type Constant not supported in AOT.");6022}6023loadSymbol(TR::aload, symRefTab()->findOrCreateMethodTypeSymbol(_methodSymbol, cpIndex));6024}6025break;6026default:6027break;6028}6029}60306031void6032TR_J9ByteCodeIlGenerator::loadFromCallSiteTable(int32_t callSiteIndex)6033{6034TR::SymbolReference *symRef = symRefTab()->findOrCreateCallSiteTableEntrySymbol(_methodSymbol, callSiteIndex);6035TR::Node *load = loadSymbol(TR::aload, symRef);6036if (!symRef->isUnresolved())6037{6038if (_methodSymbol->getResolvedMethod()->callSiteTableEntryAddress(callSiteIndex))6039load->setIsNonNull(true);6040else6041load->setIsNull(true);6042}6043}60446045void6046TR_J9ByteCodeIlGenerator::loadArrayElement(TR::DataType dataType, TR::ILOpCodes nodeop, bool checks, bool mayBeValueType)6047{6048// Value types prototype for flattened array elements does not yet support6049// GC policies that allow arraylets. If arraylets are required, assume6050// we won't have flattening, so no call to flattenable array element access6051// helper is needed.6052//6053if (mayBeValueType && TR::Compiler->om.areValueTypesEnabled() && !TR::Compiler->om.canGenerateArraylets() && dataType == TR::Address)6054{6055TR::Node* elementIndex = pop();6056TR::Node* arrayBaseAddress = pop();6057if (!arrayBaseAddress->isNonNull())6058{6059auto* nullchk = TR::Node::create(TR::PassThrough, 1, arrayBaseAddress);6060nullchk = genNullCheck(nullchk);6061genTreeTop(nullchk);6062}6063auto* helperSymRef = comp()->getSymRefTab()->findOrCreateLoadFlattenableArrayElementSymbolRef();6064auto* helperCallNode = TR::Node::createWithSymRef(TR::acall, 2, 2, elementIndex, arrayBaseAddress, helperSymRef);60656066TR::TreeTop *loadHelperCallTT = genTreeTop(helperCallNode);60676068const char *counterName = TR::DebugCounter::debugCounterName(comp(), "vt-helper/generated/aaload/(%s)/bc=%d",6069comp()->signature(), currentByteCodeIndex());6070TR::DebugCounter::prependDebugCounter(comp(), counterName, loadHelperCallTT);60716072push(helperCallNode);6073return;6074}60756076bool genSpineChecks = comp()->requiresSpineChecks();60776078_suppressSpineChecks = false;60796080calculateArrayElementAddress(dataType, checks);60816082TR::Node * arrayBaseAddress = pop();6083TR::Node * elementAddress = pop();60846085TR::Node *element = NULL;6086TR::SymbolReference * elementSymRef = symRefTab()->findOrCreateArrayShadowSymbolRef(dataType, arrayBaseAddress);6087element = TR::Node::createWithSymRef(nodeop, 1, 1, elementAddress, elementSymRef);60886089// For hybrid arrays, an incomplete check node may have been pushed on the stack.6090// It may not exist if the bound and spine check have been skipped.6091//6092TR::Node *checkNode = NULL;60936094if (genSpineChecks && !_stack->isEmpty())6095{6096if (_stack->top()->getOpCode().isSpineCheck())6097{6098checkNode = pop();6099}6100}61016102if (dataType == TR::Address)6103{61046105if (comp()->useCompressedPointers())6106{6107// Returns non-null if the compressedRefs anchor is going to6108// be part of the subtrees6109//6110// We don't want this in a separate treetop for hybrid arraylets.6111//6112TR::Node *newElement = genCompressedRefs(element);6113if (newElement)6114element = newElement;6115}6116}61176118if (checkNode)6119{6120if (checkNode->getOpCode().isBndCheck())6121{6122TR_ASSERT(checkNode->getOpCodeValue() == TR::BNDCHKwithSpineCHK, "unexpected check node");61236124// Re-arrange children now that load and base address6125// are known.6126//6127checkNode->setChild(2, checkNode->getChild(0)); // arraylength6128checkNode->setChild(3, checkNode->getChild(1)); // index6129}6130else6131{6132TR_ASSERT(checkNode->getOpCodeValue() == TR::SpineCHK, "unexpected check node");6133checkNode->setChild(2, checkNode->getChild(0)); // index6134}61356136checkNode->setSpineCheckWithArrayElementChild(true);6137checkNode->setAndIncChild(0, element); // array element6138checkNode->setAndIncChild(1, arrayBaseAddress); // base array6139}61406141push(element);6142}61436144void6145TR_J9ByteCodeIlGenerator::loadMonitorArg()6146{6147TR_ASSERT(_methodSymbol->isSynchronised(), "loadMonitorArg called for an nonsynchronized method");61486149// the syncObjectTemp is always initialized with the monitor argument on entry6150// to the method (regarless of whether its a static sync method or a sync method)6151// we don't want to use the syncObjectTemp always at the monexit because the monent and monexit6152// use different symRefs and this can cause problems for redundant monitor elimination.6153// we use the syncObjectTemp only when the outermost method is a DLT compile6154// for a DLT compile, if the compilation entered directly into a synchronized region, the syncObjectTemp6155// will be refreshed with the correct value in the DLT block6156//6157bool useSyncObjectTemp = comp()->isDLT() && _methodSymbol == comp()->getJittedMethodSymbol();61586159if (_methodSymbol->isStatic())6160loadSymbol(TR::loadaddr, symRefTab()->findOrCreateClassSymbol(_methodSymbol, 0, method()->containingClass()));6161else if (useSyncObjectTemp && _methodSymbol->getSyncObjectTemp())6162loadSymbol(TR::aload, _methodSymbol->getSyncObjectTemp());6163else6164loadAuto(TR::Address, 0); // get this pointer6165}61666167//----------------------------------------------6168// gen monitor6169//----------------------------------------------61706171void6172TR_J9ByteCodeIlGenerator::genMonitorEnter()6173{6174TR::SymbolReference * monitorEnterSymbolRef = symRefTab()->findOrCreateMonitorEntrySymbolRef(_methodSymbol);61756176TR::Node * node = pop();61776178bool isStatic = (node->getOpCodeValue() == TR::loadaddr && node->getSymbol()->isClassObject());61796180if (isStatic)6181node = TR::Node::createWithSymRef(TR::aloadi, 1, 1, node, symRefTab()->findOrCreateJavaLangClassFromClassSymbolRef());61826183TR::Node *loadNode = node;6184// We need to keep all synchronized objects on the stack. We'll create meta data that represents each locked object at each6185// gc point so that the VM can figure out which objects are locked on the stack at any given gc point6186// code moved below, so that the store happens after the monent6187/*6188if (node->getOpCodeValue() != TR::aload || !comp()->getOption(TR_DisableLiveMonitorMetadata))6189{6190TR::SymbolReference * tempSymRef = symRefTab()->createTemporary(_methodSymbol, TR::Address);6191if (!comp()->getOption(TR_DisableLiveMonitorMetadata))6192{6193tempSymRef->getSymbol()->setHoldsMonitoredObject();6194comp()->addMonitorAuto(tempSymRef->getSymbol()->castToRegisterMappedSymbol(), comp()->getCurrentInlinedSiteIndex());6195}6196genTreeTop(TR::Node::createStore(tempSymRef, node));6197node = TR::Node::createLoad(tempSymRef);6198}6199*/62006201node = TR::Node::createWithSymRef(TR::monent, 1, 1, node, monitorEnterSymbolRef);6202if (isStatic)6203node->setStaticMonitor(true);62046205genTreeTop(genNullCheck(node));62066207if (!comp()->getOption(TR_DisableLiveMonitorMetadata))6208{6209TR::SymbolReference * tempSymRef = symRefTab()->createTemporary(_methodSymbol, TR::Address);6210comp()->addAsMonitorAuto(tempSymRef, false);6211genTreeTop(TR::Node::createStore(tempSymRef, loadNode));6212}62136214_methodSymbol->setMayContainMonitors(true);6215}62166217void6218TR_J9ByteCodeIlGenerator::genMonitorExit(bool isReturn)6219{6220TR::SymbolReference * monitorExitSymbolRef = isReturn ?6221symRefTab()->findOrCreateMethodMonitorExitSymbolRef(_methodSymbol) :6222symRefTab()->findOrCreateMonitorExitSymbolRef(_methodSymbol);62236224TR::Node * node = pop();62256226bool isStatic = (node->getOpCodeValue() == TR::loadaddr && node->getSymbol()->isClassObject());6227///bool isStatic = _methodSymbol->isStatic();62286229if (isStatic)6230node = TR::Node::createWithSymRef(TR::aloadi, 1, 1, node, symRefTab()->findOrCreateJavaLangClassFromClassSymbolRef());62316232if (!comp()->getOption(TR_DisableLiveMonitorMetadata))6233{6234genTreeTop(TR::Node::create(TR::monexitfence,0));6235}6236node = TR::Node::createWithSymRef(TR::monexit, 1, 1, node, monitorExitSymbolRef);62376238if (isReturn)6239{6240if (_methodSymbol->isStatic())6241node->setStaticMonitor(true);62426243node->setSyncMethodMonitor(true);62446245TR_OpaqueClassBlock * owningClass = _methodSymbol->getResolvedMethod()->containingClass();6246if (owningClass != comp()->getObjectClassPointer())6247node->setSecond((TR::Node*)owningClass);62486249_implicitMonitorExits.add(node);6250}62516252node = genNullCheck(node);62536254// The monitor exit will unlock the class object which will allow other threads to modify the6255// fields in this class. To ensure that any fields referenced by the return are evaluated6256// before the monitor exit call the shadows symbols on the stack must be anchored before the6257// monitor exit call.6258//6259handleSideEffect(node);62606261genTreeTop(node);6262_methodSymbol->setMayContainMonitors(true);6263}62646265//----------------------------------------------6266// gen new6267//----------------------------------------------62686269void6270TR_J9ByteCodeIlGenerator::genNew(int32_t cpIndex)6271{6272loadClassObject(cpIndex);6273genNew();6274}62756276void6277TR_J9ByteCodeIlGenerator::genNew(TR::ILOpCodes opCode)6278{6279TR::Node *node = TR::Node::createWithSymRef(opCode, 1, 1, pop(),symRefTab()->findOrCreateNewObjectSymbolRef(_methodSymbol));6280_methodSymbol->setHasNews(true);6281genTreeTop(node);6282push(node);62836284bool skipFlush = false;6285if (!node->getFirstChild()->getSymbolReference()->isUnresolved() && node->getFirstChild()->getSymbol()->isStatic())6286{6287TR_OpaqueClassBlock *clazz = (TR_OpaqueClassBlock*)node->getFirstChild()->getSymbol()->castToStaticSymbol()->getStaticAddress();6288int32_t len;6289char *sig;6290sig = TR::Compiler->cls.classSignature_DEPRECATED(comp(), clazz, len, comp()->trMemory());6291OMR::ResolvedMethodSymbol *resolvedMethodSymbol = node->getSymbol()->getResolvedMethodSymbol();62926293if (((len == 16) && strncmp(sig, "Ljava/lang/Long;", 16) == 0) ||6294((len == 16) && strncmp(sig, "Ljava/lang/Byte;", 16) == 0) ||6295((len == 17) && strncmp(sig, "Ljava/lang/Short;", 17) == 0) ||6296((len == 18) && strncmp(sig, "Ljava/lang/String;", 18) == 0) ||6297((len == 19) && strncmp(sig, "Ljava/lang/Integer;", 19) == 0) ||6298((len == 19) && strncmp(sig, "Ljava/util/HashMap;", 19) == 0) ||6299((len == 21) && strncmp(sig, "Ljava/lang/Character;", 21) == 0) ||6300((len == 21) && strncmp(sig, "Ljava/nio/CharBuffer;", 21) == 0) ||6301((len == 21) && strncmp(sig, "Ljava/nio/ByteBuffer;", 21) == 0) ||6302((len == 24) && strncmp(sig, "Ljava/util/HashMap$Node;", 24) == 0) ||6303((len == 25) && strncmp(sig, "Ljava/util/ArrayList$Itr;", 25) == 0) ||6304((len == 25) && strncmp(sig, "Ljava/nio/HeapCharBuffer;", 25) == 0) ||6305((len == 25) && strncmp(sig, "Ljava/nio/HeapByteBuffer;", 25) == 0) ||6306((len == 25) && strncmp(sig, "Ljava/util/LinkedHashMap;", 25) == 0) ||6307((len == 26) && strncmp(sig, "Ljava/util/HashMap$KeySet;", 26) == 0) ||6308((len == 27) && strncmp(sig, "Ljava/util/Hashtable$Entry;", 27) == 0) ||6309((len == 28) && strncmp(sig, "Ljava/util/AbstractList$Itr;", 28) == 0) ||6310((len == 28) && strncmp(sig, "Ljava/util/HashMap$EntrySet;", 28) == 0) ||6311((len == 30) && strncmp(sig, "Ljava/util/LinkedList$ListItr;", 30) == 0) ||6312((len == 31) && strncmp(sig, "Ljava/util/HashMap$KeyIterator;", 31) == 0) ||6313((len == 32) && strncmp(sig, "Ljava/util/HashMap$HashIterator;", 32) == 0) ||6314((len == 33) && strncmp(sig, "Ljava/util/HashMap$ValueIterator;", 33) == 0) ||6315((len == 33) && strncmp(sig, "Ljava/util/HashMap$EntryIterator;", 33) == 0) ||6316((len == 33) && strncmp(sig, "Ljava/nio/charset/CharsetDecoder;", 33) == 0) ||6317((len == 35) && strncmp(sig, "Ljavax/servlet/ServletRequestEvent;", 35) == 0) ||6318((len == 44) && strncmp(sig, "Ljavax/servlet/ServletRequestAttributeEvent;", 44) == 0) ||6319((len == 45) && strncmp(sig, "Ljava/util/concurrent/ConcurrentHashMap$Node;", 45) == 0) ||6320((len == 53) && strncmp(sig, "Ljavax/faces/component/_DeltaStateHelper$InternalMap;", 53) == 0) ||6321((len == 55) && strncmp(sig, "Ljava/util/concurrent/CopyOnWriteArrayList$COWIterator;", 55) == 0) ||6322((len == 68) && strncmp(sig, "Ljava/util/concurrent/locks/ReentrantReadWriteLock$Sync$HoldCounter;", 68) == 0) ||6323((len == 25) && strncmp(sig, "Ljava/util/PriorityQueue;", 25) == 0) ||6324((len == 42) && strncmp(sig, "Ljava/util/concurrent/locks/ReentrantLock;", 42) == 0) ||6325((len == 54) && strncmp(sig, "Ljava/util/concurrent/locks/ReentrantLock$NonfairSync;", 54) == 0)6326)6327{6328skipFlush = true;6329}6330}63316332if (!skipFlush)6333genFlush(0);6334}63356336void6337TR_J9ByteCodeIlGenerator::genWithField(uint16_t fieldCpIndex)6338{6339const int32_t bcIndex = currentByteCodeIndex();6340int32_t classCpIndex = method()->classCPIndexOfFieldOrStatic(fieldCpIndex);6341TR_OpaqueClassBlock *valueClass = method()->getClassFromConstantPool(comp(), classCpIndex, true);6342if (!valueClass)6343{6344abortForUnresolvedValueTypeOp("withfield", "class");6345}63466347TR_ResolvedJ9Method * owningMethod = static_cast<TR_ResolvedJ9Method*>(_methodSymbol->getResolvedMethod());6348if (owningMethod->isFieldQType(fieldCpIndex) && owningMethod->isFieldFlattened(comp(), fieldCpIndex, _methodSymbol->isStatic()))6349{6350return comp()->getOption(TR_UseFlattenedFieldRuntimeHelpers) ?6351genFlattenableWithFieldWithHelper(fieldCpIndex) :6352genFlattenableWithField(fieldCpIndex, valueClass);6353}63546355bool isStore = false;6356TR::SymbolReference * symRef = symRefTab()->findOrCreateShadowSymbol(_methodSymbol, fieldCpIndex, isStore);6357if (symRef->isUnresolved())6358{6359abortForUnresolvedValueTypeOp("withfield", "field");6360}63616362genWithField(symRef, valueClass);6363}63646365void6366TR_J9ByteCodeIlGenerator::genWithField(TR::SymbolReference * symRef, TR_OpaqueClassBlock * valueClass)6367{6368TR::Node *newFieldValue = pop();6369TR::Node *originalObject = pop();63706371/*6372* Insert nullchk for the original object as requested by the JVM spec.6373* Especially in case of value type class with a single field, the nullchk is still6374* necessary even though the original object is actually not needed.6375*/6376TR::Node *passThruNode = TR::Node::create(TR::PassThrough, 1, originalObject);6377genTreeTop(genNullCheck(passThruNode));63786379loadClassObject(valueClass);6380const TR::TypeLayout *typeLayout = comp()->typeLayout(valueClass);6381size_t fieldCount = typeLayout->count();63826383for (size_t idx = 0; idx < fieldCount; idx++)6384{6385const TR::TypeLayoutEntry &fieldEntry = typeLayout->entry(idx);6386if (fieldEntry._offset == symRef->getOffset())6387push(newFieldValue);6388else6389{6390auto* fieldSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(valueClass,6391fieldEntry._datatype,6392fieldEntry._offset,6393fieldEntry._isVolatile,6394fieldEntry._isPrivate,6395fieldEntry._isFinal,6396fieldEntry._fieldname,6397fieldEntry._typeSignature6398);6399push(originalObject);6400loadInstance(fieldSymRef);6401}6402}64036404TR::Node *newValueNode = genNodeAndPopChildren(TR::newvalue, fieldCount+1, symRefTab()->findOrCreateNewValueSymbolRef(_methodSymbol));6405newValueNode->setIdentityless(true);6406genTreeTop(newValueNode);6407push(newValueNode);6408genFlush(0);6409}64106411void6412TR_J9ByteCodeIlGenerator::genFlattenableWithFieldWithHelper(uint16_t fieldCpIndex)6413{6414bool isStore = false;6415TR::SymbolReference * symRef = symRefTab()->findOrCreateShadowSymbol(_methodSymbol, fieldCpIndex, isStore);6416if (symRef->isUnresolved())6417{6418abortForUnresolvedValueTypeOp("withfield", "field");6419}64206421TR::Node *newFieldValue = pop();6422TR::Node *originalObject = pop();64236424/*6425* Insert nullchk for the original object as requested by the JVM spec.6426* Especially in case of value type class with a single field, the nullchk is still6427* necessary even though the original object is actually not needed.6428*/6429TR::Node *passThruNode = TR::Node::create(TR::PassThrough, 1, originalObject);6430genTreeTop(genNullCheck(passThruNode));64316432auto* j9ResolvedMethod = static_cast<TR_ResolvedJ9Method *>(_methodSymbol->getResolvedMethod());6433auto* ramFieldRef = reinterpret_cast<J9RAMFieldRef*>(j9ResolvedMethod->cp()) + fieldCpIndex;6434auto* ramFieldRefNode = TR::Node::aconst(reinterpret_cast<uintptr_t>(ramFieldRef));6435auto* helperCallNode = TR::Node::createWithSymRef(TR::acall, 3, 3, newFieldValue, originalObject, ramFieldRefNode, comp()->getSymRefTab()->findOrCreateWithFlattenableFieldSymbolRef());6436handleSideEffect(helperCallNode);6437genTreeTop(helperCallNode);6438push(helperCallNode);6439}64406441static TR::SymbolReference * createLoadFieldSymRef(TR::Compilation * comp, TR_OpaqueClassBlock * fieldClass, const char * fieldname)6442{6443const TR::TypeLayout *fieldClassLayout = comp->typeLayout(fieldClass);6444size_t fieldClassFieldCount = fieldClassLayout->count();64456446for (size_t idx = 0; idx < fieldClassFieldCount; idx++)6447{6448const TR::TypeLayoutEntry &fieldEntry = fieldClassLayout->entry(idx);6449if (!strcmp(fieldname, fieldEntry._fieldname))6450{6451auto * fieldSymRef = comp->getSymRefTab()->findOrFabricateShadowSymbol(fieldClass,6452fieldEntry._datatype,6453fieldEntry._offset,6454fieldEntry._isVolatile,6455fieldEntry._isPrivate,6456fieldEntry._isFinal,6457fieldEntry._fieldname,6458fieldEntry._typeSignature6459);6460return fieldSymRef;6461}6462}64636464TR_ASSERT_FATAL(false, "Did not find the matching fieldname %s", fieldname);6465return NULL;6466}64676468void6469TR_J9ByteCodeIlGenerator::genFlattenableWithField(uint16_t fieldCpIndex, TR_OpaqueClassBlock * valueClass)6470{6471/* An example on what the tree with flattened fields would look like6472*6473* value Point2D {6474* public final int x;6475* public final int y;6476* }6477*6478* value FlattenedLine2D {6479* public final Point2D st;6480* public final Point2D en;6481*6482* public static FlattenedLine2D withSt(FlattenedLine2D line, Point2D st) {6483* 0: aload_16484* 1: aload_06485* 3: withfield #3 // Field st:QPoint2D;6486* 6: astore_26487* 7: aload_26488* 8: areturn6489* }6490* }6491*6492* method="FlattenedLine2D.withSt(QFlattenedLine2D;QPoint2D;)QFlattenedLine2D;"6493* 3: JBwithfield6494* /--- trees inserted ------------------------6495* n7n ( 0) NULLCHK on n3n [#32]6496* n6n ( 2) iloadi Point2D.x I[#355 final Point2D.x I +4]6497* n3n ( 2) aload <parm 1 F>[#353 Parm]6498* n9n ( 0) NULLCHK on n3n [#32]6499* n8n ( 2) iloadi Point2D.y I[#356 final Point2D.y I +8]6500* n3n ( 2) ==>aload6501* n11n ( 0) NULLCHK on n4n [#32]6502* n10n ( 2) iloadi FlattenedLine2D.en.x I[#357 final FlattenedLine2D.en.x I +12]6503* n4n ( 2) aload <parm 0 Q>[#352 Parm]6504* n13n ( 0) NULLCHK on n4n [#32]6505* n12n ( 2) iloadi FlattenedLine2D.en.y I[#358 final FlattenedLine2D.en.y I +16]6506* n4n ( 2) ==>aload6507* n15n ( 0) treetop6508* n14n ( 1) newvalue jitNewValue[#100 helper Method]6509* n5n ( 1) loadaddr FlattenedLine2D[#354 Static]6510* n6n ( 2) ==>iloadi6511* n8n ( 2) ==>iloadi6512* n10n ( 2) ==>iloadi6513* n12n ( 2) ==>iloadi6514* /--- stack after ------------------------6515* @0 n14n ( 1) ==>newvalue (Identityless sharedMemory )6516* ============================================================6517*/6518TR_ResolvedJ9Method * owningMethod = static_cast<TR_ResolvedJ9Method*>(_methodSymbol->getResolvedMethod());65196520if (isFieldResolved(comp(), owningMethod, fieldCpIndex, false))6521{6522TR::Node *newFieldValue = pop();6523TR::Node *originalObject = pop();65246525int32_t prefixLen = 0;6526char * fieldNamePrefix = getTopLevelPrefixForFlattenedFields(owningMethod, fieldCpIndex, prefixLen, comp()->trMemory()->currentStackRegion());65276528int len;6529const char * fieldClassChars = owningMethod->fieldSignatureChars(fieldCpIndex, len);6530TR_OpaqueClassBlock * fieldClass = fej9()->getClassFromSignature(fieldClassChars, len, owningMethod);65316532loadClassObject(valueClass);65336534const TR::TypeLayout *typeLayout = comp()->typeLayout(valueClass);6535size_t fieldCount = typeLayout->count();65366537TR_OpaqueClassBlock * containingClass = owningMethod->definingClassFromCPFieldRef(comp(), fieldCpIndex, _methodSymbol->isStatic());65386539for (size_t idx = 0; idx < fieldCount; idx++)6540{6541const TR::TypeLayoutEntry &fieldEntry = typeLayout->entry(idx);6542if (!strncmp(fieldNamePrefix, fieldEntry._fieldname, prefixLen))6543{6544const char * fieldNameRemovedTopLevelPrefix = fieldEntry._fieldname + prefixLen;6545auto * newFieldValueSymRef = createLoadFieldSymRef(comp(), fieldClass, fieldNameRemovedTopLevelPrefix);65466547if (comp()->getOption(TR_TraceILGen))6548{6549traceMsg(comp(), "Withfield flattened field %s\n - field[%d] name %s type %d offset %d\n",6550comp()->getDebug()->getName(newFieldValueSymRef), idx, fieldEntry._fieldname,6551fieldEntry._datatype.getDataType(), fieldEntry._offset);6552}65536554push(newFieldValue);6555loadInstance(newFieldValueSymRef);6556}6557else6558{6559auto * fieldSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(valueClass,6560fieldEntry._datatype,6561fieldEntry._offset,6562fieldEntry._isVolatile,6563fieldEntry._isPrivate,6564fieldEntry._isFinal,6565fieldEntry._fieldname,6566fieldEntry._typeSignature6567);6568push(originalObject);6569loadInstance(fieldSymRef);6570}6571}65726573TR::Node *newValueNode = genNodeAndPopChildren(TR::newvalue, fieldCount+1, symRefTab()->findOrCreateNewValueSymbolRef(_methodSymbol));6574newValueNode->setIdentityless(true);6575genTreeTop(newValueNode);6576push(newValueNode);6577genFlush(0);65786579return;6580}6581else6582{6583abortForUnresolvedValueTypeOp("withfield", "field");6584}6585}65866587void6588TR_J9ByteCodeIlGenerator::genAconst_init(uint16_t cpIndex)6589{6590TR_OpaqueClassBlock *valueTypeClass = method()->getClassFromConstantPool(comp(), cpIndex);6591genAconst_init(valueTypeClass);6592}65936594void6595TR_J9ByteCodeIlGenerator::genAconst_init(TR_OpaqueClassBlock *valueTypeClass)6596{6597// valueTypeClass will be NULL if it is unresolved. Abort the compilation and6598// track the failure with a static debug counter6599if (valueTypeClass == NULL)6600{6601abortForUnresolvedValueTypeOp("aconst_init", "class");6602}66036604TR::SymbolReference *valueClassSymRef = symRefTab()->findOrCreateClassSymbol(_methodSymbol, 0, valueTypeClass);66056606if (comp()->getOption(TR_TraceILGen))6607{6608traceMsg(comp(), "Handling aconst_init for valueClass %s\n", comp()->getDebug()->getName(valueClassSymRef));6609}66106611loadSymbol(TR::loadaddr, valueClassSymRef);66126613TR::Node *newValueNode = NULL;66146615if (valueClassSymRef->isUnresolved())6616{6617// IL generation for aconst_init is currently only able to handle value type classes that have been resolved.6618// If the class is still unresolved, abort the compilation and track the failure with a static debug counter.6619abortForUnresolvedValueTypeOp("aconst_init", "class");6620}6621else6622{6623const TR::TypeLayout *typeLayout = comp()->typeLayout(valueTypeClass);6624size_t fieldCount = typeLayout->count();66256626for (size_t idx = 0; idx < fieldCount; idx++)6627{6628const TR::TypeLayoutEntry &entry = typeLayout->entry(idx);66296630if (comp()->getOption(TR_TraceILGen))6631{6632traceMsg(comp(), "Handling aconst_init for valueClass %s\n - field[%d] name %s type %d offset %d\n", comp()->getDebug()->getName(valueClassSymRef), idx, entry._fieldname, entry._datatype.getDataType(), entry._offset);6633}66346635// Supply default value that is appropriate for the type of the corresponding field6636// All these are gathered up as operands of a newvalue instruction.6637//6638// For example, if a value type class "Val" has fields of type int, long, double, LIdent;6639// and Qval2;, where value type class "Val2" has a field of type boolean, the following6640// IL will be generated:6641//6642// newvalue jitNewValue // Default value of type Val6643// loadaddr Val6644// iconst 0 // int default value6645// lconst 0 // long default value6646// dconst 0.0 // double default value6647// aconst 0 // default value (null reference) for class Ident6648// newvalue jitNewValue // Default value of type Val26649// loadaddr Val26650// iconst 0 // boolean default value6651//6652switch (entry._datatype.getDataType())6653{6654case TR::Int8:6655case TR::Int16:6656case TR::Int32:6657{6658loadConstant(TR::iconst, 0);6659break;6660}6661case TR::Int64:6662{6663loadConstant(TR::lconst, (int64_t) 0ll);6664break;6665}6666case TR::Float:6667{6668loadConstant(TR::fconst, 0.0f);6669break;6670}6671case TR::Double:6672{6673loadConstant(TR::dconst, 0.0);6674break;6675}6676case TR::Address:6677{6678const char *fieldSignature = entry._typeSignature;66796680// If the field's signature begins with a Q, it is a value type and should be initialized with a default value6681// for that value type. That's handled with a recursive call to genAconst_init.6682// If the signature does not begin with a Q, the field is an identity type whose default value is a Java null6683/// reference.6684if (fieldSignature[0] == 'Q')6685{6686TR_OpaqueClassBlock *fieldClass = fej9()->getClassFromSignature(fieldSignature, (int32_t)strlen(fieldSignature),6687comp()->getCurrentMethod());6688genAconst_init(fieldClass);6689}6690else if (comp()->target().is64Bit())6691{6692loadConstant(TR::aconst, (int64_t)0);6693}6694else6695{6696loadConstant(TR::aconst, (int32_t)0);6697}6698break;6699}6700default:6701{6702TR_ASSERT_FATAL(false, "Unexpected type for aconst_init field\n");6703}6704}6705}67066707newValueNode = genNodeAndPopChildren(TR::newvalue, fieldCount+1, symRefTab()->findOrCreateNewValueSymbolRef(_methodSymbol));6708newValueNode->setIdentityless(true);6709}67106711genTreeTop(newValueNode);6712push(newValueNode);6713genFlush(0);6714}67156716void6717TR_J9ByteCodeIlGenerator::genNewArray(int32_t typeIndex)6718{6719loadConstant(TR::iconst, typeIndex);67206721TR::Node * secondChild=pop();6722TR::Node * firstChild=pop();6723TR::Node * node = TR::Node::createWithSymRef(TR::newarray, 2, 2, firstChild, secondChild, symRefTab()->findOrCreateNewArraySymbolRef(_methodSymbol));67246725if (_methodSymbol->skipZeroInitializationOnNewarrays())6726node->setCanSkipZeroInitialization(true);67276728bool generateArraylets = comp()->generateArraylets();67296730// special case for handling Arrays.copyOf in the StringEncoder fast paths for Java 9+6731if (!comp()->isOutermostMethod() && !comp()->isPeekingMethod()6732&& !generateArraylets6733&& _methodSymbol->getRecognizedMethod() == TR::java_util_Arrays_copyOf_byte)6734{6735int32_t callerIndex = comp()->getCurrentInlinedCallSite()->_byteCodeInfo.getCallerIndex();6736TR::ResolvedMethodSymbol *caller = callerIndex > -1 ? comp()->getInlinedResolvedMethodSymbol(callerIndex) : comp()->getMethodSymbol();6737switch (caller->getRecognizedMethod())6738{6739case TR::java_lang_StringCoding_encode8859_1:6740case TR::java_lang_StringCoding_encodeASCII:6741case TR::java_lang_String_encodeASCII:6742case TR::java_lang_StringCoding_encodeUTF8:6743node->setCanSkipZeroInitialization(true);6744break;67456746default:6747break;6748}6749}67506751bool separateInitializationFromAllocation;6752switch (_methodSymbol->getRecognizedMethod())6753{6754case TR::java_util_Arrays_copyOf_byte:6755case TR::java_util_Arrays_copyOf_short:6756case TR::java_util_Arrays_copyOf_char:6757case TR::java_util_Arrays_copyOf_int:6758case TR::java_util_Arrays_copyOf_long:6759case TR::java_util_Arrays_copyOf_float:6760case TR::java_util_Arrays_copyOf_double:6761case TR::java_util_Arrays_copyOf_boolean:6762case TR::java_util_Arrays_copyOfRange_byte:6763case TR::java_util_Arrays_copyOfRange_short:6764case TR::java_util_Arrays_copyOfRange_char:6765case TR::java_util_Arrays_copyOfRange_int:6766case TR::java_util_Arrays_copyOfRange_long:6767case TR::java_util_Arrays_copyOfRange_float:6768case TR::java_util_Arrays_copyOfRange_double:6769case TR::java_util_Arrays_copyOfRange_boolean:6770separateInitializationFromAllocation = true;6771break;6772default:6773separateInitializationFromAllocation = false;6774break;6775}67766777TR::Node *initNode = NULL;67786779if (!comp()->getOption(TR_DisableSeparateInitFromAlloc) &&6780!node->canSkipZeroInitialization() &&6781!generateArraylets && separateInitializationFromAllocation &&6782comp()->cg()->getSupportsArraySet())6783{6784node->setCanSkipZeroInitialization(true);67856786TR::Node *arrayRefNode;6787int32_t hdrSize = (int32_t) TR::Compiler->om.contiguousArrayHeaderSizeInBytes();6788bool is64BitTarget = comp()->target().is64Bit();67896790if (is64BitTarget)6791{6792TR::Node *constantNode = TR::Node::create(node, TR::lconst);6793constantNode->setLongInt((int64_t)hdrSize);6794arrayRefNode = TR::Node::create(TR::aladd, 2, node, constantNode);6795}6796else6797arrayRefNode = TR::Node::create(TR::aiadd, 2, node, TR::Node::create(node, TR::iconst, 0, hdrSize));67986799arrayRefNode->setIsInternalPointer(true);68006801TR::Node *sizeInBytes;6802TR::Node *sizeNode = node->getFirstChild();68036804TR::Node* constValNode = TR::Node::bconst(node, (int8_t)0);6805int32_t elementSize = TR::Compiler->om.getSizeOfArrayElement(node);68066807if (is64BitTarget)6808{6809TR::Node *stride = TR::Node::create(node, TR::lconst);6810stride->setLongInt((int64_t) elementSize);6811TR::Node *i2lNode = TR::Node::create(TR::i2l, 1, sizeNode);6812sizeInBytes = TR::Node::create(TR::lmul, 2, i2lNode, stride);6813}6814else6815{6816TR::Node *stride = TR::Node::create(node, TR::iconst, 0, elementSize);6817sizeInBytes = TR::Node::create(TR::imul, 2, sizeNode, stride);6818}68196820TR::Node *arraysetNode = TR::Node::create(TR::arrayset, 3, arrayRefNode, constValNode, sizeInBytes);6821TR::SymbolReference *arraySetSymRef = comp()->getSymRefTab()->findOrCreateArraySetSymbol();6822arraysetNode->setSymbolReference(arraySetSymRef);6823arraysetNode->setArraysetLengthMultipleOfPointerSize(true);68246825initNode = TR::Node::create(TR::treetop, 1, arraysetNode);6826}68276828_methodSymbol->setHasNews(true);6829genTreeTop(node);6830if (initNode)6831genTreeTop(initNode);6832push(node);6833genFlush(0);6834}68356836void6837TR_J9ByteCodeIlGenerator::genANewArray(int32_t cpIndex)6838{6839loadClassObject(cpIndex);6840genANewArray();6841}68426843void6844TR_J9ByteCodeIlGenerator::genANewArray()6845{6846TR::Node * secondChild=pop();6847TR::Node * firstChild=pop();6848TR::Node * node = TR::Node::createWithSymRef(TR::anewarray, 2, 2, firstChild, secondChild, symRefTab()->findOrCreateANewArraySymbolRef(_methodSymbol));6849_methodSymbol->setHasNews(true);6850genTreeTop(node);6851push(node);6852genFlush(0);6853}68546855void6856TR_J9ByteCodeIlGenerator::genMultiANewArray(int32_t cpIndex, int32_t dims)6857{6858// total number of params is 2+#dims6859//6860loadClassObject(cpIndex);6861genMultiANewArray(dims);6862}68636864void6865TR_J9ByteCodeIlGenerator::genMultiANewArray(int32_t dims)6866{6867// total number of params is 2+#dims6868//6869TR::Node *node = genNodeAndPopChildren(TR::multianewarray, dims+2, symRefTab()->findOrCreateMultiANewArraySymbolRef(_methodSymbol), 1);68706871_methodSymbol->setHasNews(true);6872// Make number of dimensions the first parameter6873//6874loadConstant(TR::iconst, dims);6875node->setAndIncChild(0, pop());68766877genTreeTop(node);6878push(node);6879}68806881//----------------------------------------------6882// genReturn6883//----------------------------------------------68846885int32_t6886TR_J9ByteCodeIlGenerator::genReturn(TR::ILOpCodes nodeop, bool monitorExit)6887{6888if (!comp()->isPeekingMethod() &&6889(_methodSymbol->getMandatoryRecognizedMethod() == TR::java_lang_Object_init))6890{6891TR::Node *receiverArg = NULL;6892if (_methodSymbol->getThisTempForObjectCtor())6893receiverArg = TR::Node::createLoad(_methodSymbol->getThisTempForObjectCtor());6894else6895{6896loadAuto(TR::Address, 0);6897receiverArg = pop();6898}6899TR::SymbolReference *finalizeSymRef = comp()->getSymRefTab()->findOrCreateRuntimeHelper(TR_jitCheckIfFinalizeObject, true, true, true);6900TR::Node *vcallNode = TR::Node::createWithSymRef(TR::call, 1, 1, receiverArg, finalizeSymRef);6901_finalizeCallsBeforeReturns.add(vcallNode);6902genTreeTop(vcallNode);6903}69046905static const char* disableMethodHookForCallees = feGetEnv("TR_DisableMethodHookForCallees");6906if ((fej9()->isMethodTracingEnabled(_methodSymbol->getResolvedMethod()->getPersistentIdentifier())6907|| (!comp()->getOption(TR_FullSpeedDebug)6908&& TR::Compiler->vm.canMethodExitEventBeHooked(comp())))6909&& (isOutermostMethod() || !disableMethodHookForCallees))6910{6911TR::SymbolReference * methodExitSymRef = symRefTab()->findOrCreateReportMethodExitSymbolRef(_methodSymbol);69126913TR::Node * methodExitNode;6914if (nodeop == TR::Return)6915{6916loadConstant(TR::aconst, (void *)0);6917methodExitNode = TR::Node::createWithSymRef(TR::MethodExitHook, 1, 1, pop(), methodExitSymRef);6918}6919else6920{6921TR::Node * returnValue = _stack->top();6922TR::SymbolReference * tempSymRef = symRefTab()->createTemporary(_methodSymbol, getDataType(returnValue));6923genTreeTop(TR::Node::createStore(tempSymRef, returnValue));6924methodExitNode = TR::Node::createWithSymRef(TR::MethodExitHook, 1, 1, TR::Node::createWithSymRef(TR::loadaddr, 0, tempSymRef), methodExitSymRef);6925}69266927genTreeTop(methodExitNode);6928}692969306931if (comp()->getOption(TR_EnableThisLiveRangeExtension))6932{6933if (!_methodSymbol->isStatic() &&6934(!fej9()->isClassFinal(_methodSymbol->getResolvedMethod()->containingClass()) ||6935fej9()->hasFinalizer(_methodSymbol->getResolvedMethod()->containingClass())))6936{6937loadAuto(TR::Address, 0);6938TR::SymbolReference *tempSymRef = symRefTab()->findOrCreateThisRangeExtensionSymRef(comp()->getMethodSymbol());6939genTreeTop(TR::Node::createStore(tempSymRef, pop()));6940}6941}69426943if (monitorExit && _methodSymbol->isSynchronised())6944{6945if (!isOutermostMethod())6946{6947// the monitor exit in an inlined method must be in a separate block so that the generated exception range6948// doesn't include it.6949//6950genTarget(_bcIndex);6951setupBBStartContext(_bcIndex);6952//printf("create a separate block for %s being inlined into %s\n", _methodSymbol->signature(trMemory()), comp()->signature());6953}69546955loadMonitorArg();6956genMonitorExit(true);6957}69586959if (nodeop == TR::Return)6960{6961genTreeTop(TR::Node::create(nodeop, 0));6962}6963else6964{6965TR::Node* returnChild = pop();69666967switch (current())6968{6969case J9BCReturnC:6970returnChild = TR::Node::create(TR::su2i, 1, TR::Node::create(TR::i2s, 1, returnChild));6971break;69726973case J9BCReturnS:6974returnChild = TR::Node::create(TR::s2i, 1, TR::Node::create(TR::i2s, 1, returnChild));6975break;69766977case J9BCReturnB:6978returnChild = TR::Node::create(TR::b2i, 1, TR::Node::create(TR::i2b, 1, returnChild));6979break;69806981case J9BCReturnZ:6982returnChild = TR::Node::create(TR::iand, 2, returnChild, TR::Node::iconst(1));6983break;69846985default:6986break;6987}69886989genTreeTop(TR::Node::create(nodeop, 1, returnChild));6990}69916992discardEntireStack();69936994return findNextByteCodeToGen();6995}69966997static bool storeCanBeRemovedForUnreadField(TR_PersistentFieldInfo * fieldInfo, TR::Node *node)6998{6999if (!fieldInfo ||7000!fieldInfo->isNotRead())7001return false;70027003// PR 78765: It's generally not safe to remove field stores because we can't7004// prove that native methods won't read them. It's also not safe to remove7005// address field stores in case the stored object has a finalizer; failing7006// to store the reference can cause the finalizer to run prematurely.7007//7008// However, in certain cases, this is known to be safe, so we can detect7009// those and optimize away the stores.70107011if (node->getOpCode().isCall() &&7012!node->getSymbolReference()->isUnresolved())7013{7014if (fieldInfo->isBigDecimalType())7015{7016if ((node->getSymbol()->getResolvedMethodSymbol()->getRecognizedMethod() == TR::java_math_BigDecimal_add) ||7017(node->getSymbol()->getResolvedMethodSymbol()->getRecognizedMethod() == TR::java_math_BigDecimal_subtract) ||7018(node->getSymbol()->getResolvedMethodSymbol()->getRecognizedMethod() == TR::java_math_BigDecimal_multiply))7019return true;7020}70217022if (fieldInfo->isBigIntegerType())7023{7024if ((node->getSymbol()->getResolvedMethodSymbol()->getRecognizedMethod() == TR::java_math_BigInteger_add) ||7025(node->getSymbol()->getResolvedMethodSymbol()->getRecognizedMethod() == TR::java_math_BigInteger_subtract) ||7026(node->getSymbol()->getResolvedMethodSymbol()->getRecognizedMethod() == TR::java_math_BigInteger_multiply))7027return true;7028}7029}70307031return false;7032}70337034//----------------------------------------------7035// gen store7036//----------------------------------------------7037void7038TR_J9ByteCodeIlGenerator::storeInstance(int32_t cpIndex)7039{7040if (_generateWriteBarriersForFieldWatch && comp()->compileRelocatableCode())7041comp()->failCompilation<J9::AOTNoSupportForAOTFailure>("NO support for AOT in field watch");70427043TR_ResolvedJ9Method * owningMethod = static_cast<TR_ResolvedJ9Method*>(_methodSymbol->getResolvedMethod());7044if (TR::Compiler->om.areValueTypesEnabled() && owningMethod->isFieldQType(cpIndex))7045{7046if (!isFieldResolved(comp(), owningMethod, cpIndex, true))7047{7048abortForUnresolvedValueTypeOp("putfield", "field");7049}7050else if (owningMethod->isFieldFlattened(comp(), cpIndex, _methodSymbol->isStatic()))7051{7052return comp()->getOption(TR_UseFlattenedFieldRuntimeHelpers) ?7053storeFlattenableInstanceWithHelper(cpIndex) :7054storeFlattenableInstance(cpIndex);7055}7056}70577058TR::SymbolReference * symRef = symRefTab()->findOrCreateShadowSymbol(_methodSymbol, cpIndex, true);7059storeInstance(symRef);7060}70617062void7063TR_J9ByteCodeIlGenerator::storeInstance(TR::SymbolReference * symRef)7064{7065TR::Symbol * symbol = symRef->getSymbol();7066TR::DataType type = symbol->getDataType();70677068TR::Node * value = pop();7069TR::Node * address = pop();70707071TR::Node * addressNode = address;7072TR::Node * parentObject = address;70737074// code to handle volatiles moved to CodeGenPrep7075//7076TR::Node * node;7077if ((type == TR::Address && _generateWriteBarriersForGC) || _generateWriteBarriersForFieldWatch)7078{7079node = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectWriteBarrier(type), 3, 3, addressNode, value, parentObject, symRef);7080}7081else7082{7083if (type == TR::Int8 && symRefTab()->isFieldTypeBool(symRef))7084value = TR::Node::create(TR::iand, 2, value, TR::Node::create(TR::iconst, 0, 1));7085node = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectStore(type), 2, 2, addressNode, value, symRef);7086}70877088if (symbol->isPrivate() && _classInfo && comp()->getNeedsClassLookahead())7089{7090if (!_classInfo->getFieldInfo())7091performClassLookahead(_classInfo);70927093TR_PersistentFieldInfo * fieldInfo = _classInfo->getFieldInfo() ? _classInfo->getFieldInfo()->findFieldInfo(comp(), node, true) : NULL;7094if (storeCanBeRemovedForUnreadField(fieldInfo, value) &&7095performTransformation(comp(), "O^O CLASS LOOKAHEAD: Can skip store to instance field (that is never read) storing value %p based on class file examination\n", value))7096{7097//int32_t length;7098//char *sig = TR_ClassLookahead::getFieldSignature(comp(), symbol, symRef, length);7099//fprintf(stderr, "Skipping store for field %s in %s\n", sig, comp()->signature());7100//fflush(stderr);7101genTreeTop(value);7102genTreeTop(address);7103int32_t numChildren = node->getNumChildren();7104int32_t i = 0;7105while (i < numChildren)7106{7107node->getChild(i)->decReferenceCount();7108i++;7109}71107111if (!address->isNonNull())7112{7113TR::Node *passThruNode = TR::Node::create(TR::PassThrough, 1, address);7114genTreeTop(genNullCheck(passThruNode));7115}71167117return;7118}7119}7120if (symbol->isPrivate() && !comp()->getOptions()->realTimeGC())7121{7122TR_ResolvedMethod *method;71237124if (node->getInlinedSiteIndex() != -1)7125method = comp()->getInlinedResolvedMethod(node->getInlinedSiteIndex());7126else7127method = comp()->getCurrentMethod();71287129if (method && method->getRecognizedMethod() == TR::java_lang_ref_SoftReference_get &&7130symbol->getRecognizedField() == TR::Symbol::Java_lang_ref_SoftReference_age)7131{7132TR::Node *secondChild = node->getChild(1);7133if (secondChild && secondChild->getOpCodeValue() == TR::iconst && secondChild->getInt() == 0)7134{7135handleSideEffect(node);7136genTreeTop(node);7137genFullFence(node);7138return;7139}7140}7141}7142bool genTranslateTT = (comp()->useCompressedPointers() && (type == TR::Address));71437144if (symRef->isUnresolved())7145{7146if (!address->isNonNull())7147node = genResolveAndNullCheck(node);7148else7149node = genResolveCheck(node);71507151genTranslateTT = false;7152}7153else if (!address->isNonNull())7154{7155TR::Node *nullChkNode = genNullCheck(node);7156// in some cases a nullchk may not7157// have been generated at all for the store7158//7159if (nullChkNode != node)7160genTranslateTT = false;7161node = nullChkNode;7162}71637164handleSideEffect(node);71657166if (!genTranslateTT)7167genTreeTop(node);71687169if (comp()->useCompressedPointers() &&7170(type == TR::Address))7171{7172// - J9JIT_COMPRESSED_POINTER J9CLASS HACK-7173// remove this check when j9class is allocated on the heap7174// do not compress fields that contain class pointers7175//7176TR::Node *storeValue = node;7177if (storeValue->getOpCode().isCheck())7178storeValue = storeValue->getFirstChild();71797180if (!symRefTab()->isFieldClassObject(symRef))7181{7182// returns non-null if the compressedRefs anchor is going to7183// be part of the subtrees (for now, it is a treetop)7184//7185TR::Node *newValue = genCompressedRefs(storeValue, true, -1);7186if (newValue)7187{7188node->getSecondChild()->decReferenceCount();7189node->setAndIncChild(1, newValue);7190}7191}7192else7193genTreeTop(node);7194}7195}71967197void7198TR_J9ByteCodeIlGenerator::storeFlattenableInstanceWithHelper(int32_t cpIndex)7199{7200TR::Node * value = pop();7201TR::Node * address = pop();7202if (!address->isNonNull())7203{7204auto* nullchk = TR::Node::create(TR::PassThrough, 1, address);7205nullchk = genNullCheck(nullchk);7206genTreeTop(nullchk);7207}7208auto* j9ResolvedMethod = static_cast<TR_ResolvedJ9Method *>(_methodSymbol->getResolvedMethod());7209auto* ramFieldRef = reinterpret_cast<J9RAMFieldRef*>(j9ResolvedMethod->cp()) + cpIndex;7210auto* ramFieldRefNode = TR::Node::aconst(reinterpret_cast<uintptr_t>(ramFieldRef));7211auto* helperCallNode = TR::Node::createWithSymRef(TR::acall, 3, 3, value, address, ramFieldRefNode, comp()->getSymRefTab()->findOrCreatePutFlattenableFieldSymbolRef());7212handleSideEffect(helperCallNode);7213genTreeTop(helperCallNode);7214}72157216void7217TR_J9ByteCodeIlGenerator::storeFlattenableInstance(int32_t cpIndex)7218{7219/* An example on what the tree with flattened fields would look like7220*7221* value Point2D {7222* public final int x;7223* public final int y;7224* }7225*7226* public class Line2D {7227* public Point2D st;7228* public Point2D en;7229* }7230*7231* public void setSt(Point2D start) {7232* 0: aload_07233* 1: aload_17234* 2: putfield #7 // Field st:QPoint2D;7235* 5: return7236* }7237*7238* method="Line2D.setSt(QPoint2D;)V"7239* 2: JBputfield7240* /--- trees inserted ------------------------7241* n6n ( 0) NULLCHK on n4n [#32]7242* n5n ( 2) iloadi Point2D.x I[#355 final Point2D.x I +4]7243* n4n ( 2) aload <parm 1 Q>[#353 Parm]7244* n7n ( 0) istorei Line2D.st.x I[#354 final Line2D.st.x I +8]7245* n3n ( 2) aload <'this' parm LLine2D;>[#352 Parm]7246* n5n ( 2) ==>iloadi7247* n9n ( 0) NULLCHK on n4n [#32]7248* n8n ( 2) iloadi Point2D.y I[#357 final Point2D.y I +8]7249* n4n ( 2) ==>aload7250* n10n ( 0) istorei Line2D.st.y I[#356 final Line2D.st.y I +12]7251* n3n ( 2) ==>aload (X!=0 sharedMemory )7252* n8n ( 2) ==>iloadi7253* ---- stack after: empty -----------------7254*/7255TR_ResolvedJ9Method * owningMethod = static_cast<TR_ResolvedJ9Method*>(_methodSymbol->getResolvedMethod());72567257int32_t prefixLen = 0;7258char * fieldNamePrefix = getTopLevelPrefixForFlattenedFields(owningMethod, cpIndex, prefixLen, comp()->trMemory()->currentStackRegion());72597260TR_OpaqueClassBlock * containingClass = owningMethod->definingClassFromCPFieldRef(comp(), cpIndex, _methodSymbol->isStatic());7261const TR::TypeLayout *containingClassLayout = comp()->typeLayout(containingClass);7262size_t fieldCount = containingClassLayout->count();72637264TR::Node * value = pop();7265TR::Node * address = pop();72667267int len;7268const char *fieldClassChars = owningMethod->fieldSignatureChars(cpIndex, len);7269TR_OpaqueClassBlock * fieldClass = fej9()->getClassFromSignature(fieldClassChars, len, owningMethod);72707271for (size_t idx = 0; idx < fieldCount; idx++)7272{7273const TR::TypeLayoutEntry &fieldEntry = containingClassLayout->entry(idx);7274if (!strncmp(fieldNamePrefix, fieldEntry._fieldname, prefixLen))7275{7276auto * fieldSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(containingClass,7277fieldEntry._datatype,7278fieldEntry._offset,7279fieldEntry._isVolatile,7280fieldEntry._isPrivate,7281fieldEntry._isFinal,7282fieldEntry._fieldname,7283fieldEntry._typeSignature7284);72857286const char * fieldNameRemovedTopLevelPrefix = fieldEntry._fieldname + prefixLen;7287auto * loadFieldSymRef = createLoadFieldSymRef(comp(), fieldClass, fieldNameRemovedTopLevelPrefix);72887289if (comp()->getOption(TR_TraceILGen))7290{7291traceMsg(comp(), "Store flattened field %s to %s \n - field[%d] name %s type %d offset %d\n",7292comp()->getDebug()->getName(loadFieldSymRef), comp()->getDebug()->getName(fieldSymRef),7293idx, fieldEntry._fieldname, fieldEntry._datatype.getDataType(), fieldEntry._offset);7294}72957296push(address);7297push(value);72987299loadInstance(loadFieldSymRef);7300storeInstance(fieldSymRef);7301}7302}7303}73047305void7306TR_J9ByteCodeIlGenerator::storeStatic(int32_t cpIndex)7307{7308if (_generateWriteBarriersForFieldWatch && comp()->compileRelocatableCode())7309comp()->failCompilation<J9::AOTNoSupportForAOTFailure>("NO support for AOT in field watch");73107311_staticFieldReferenceEncountered = true;7312TR::Node * value = pop();73137314TR::SymbolReference * symRef = symRefTab()->findOrCreateStaticSymbol(_methodSymbol, cpIndex, true);7315TR::StaticSymbol * symbol = symRef->getSymbol()->castToStaticSymbol();73167317TR::DataType type = symbol->getDataType();73187319TR::Node * node;73207321TR_J9VMBase *fej9 = (TR_J9VMBase *)fe();7322if (type == TR::Int8 && symRefTab()->isStaticTypeBool(symRef))7323value = TR::Node::create(TR::iand, 2, value, TR::Node::create(TR::iconst, 0, 1));73247325if ((type == TR::Address && _generateWriteBarriersForGC) || _generateWriteBarriersForFieldWatch)7326{7327void * staticClass = method()->classOfStatic(cpIndex);7328loadSymbol(TR::loadaddr, symRefTab()->findOrCreateClassSymbol(_methodSymbol, cpIndex, staticClass, true /* cpIndexOfStatic */));73297330node = pop();7331node = TR::Node::createWithSymRef(TR::aloadi, 1, 1, node, symRefTab()->findOrCreateJavaLangClassFromClassSymbolRef());7332push(node);73337334node = TR::Node::createWithSymRef(comp()->il.opCodeForDirectWriteBarrier(type), 2, 2, value, pop(), symRef);7335}7336else if (symbol->isVolatile() && type == TR::Int64 && !symRef->isUnresolved() && comp()->target().is32Bit() &&7337!comp()->cg()->getSupportsInlinedAtomicLongVolatiles() && 0)7338{7339TR::SymbolReference *volatileLongSymRef =7340comp()->getSymRefTab()->findOrCreateRuntimeHelper (TR_volatileWriteLong, false, false, true);7341TR::Node * statics = TR::Node::createWithSymRef(TR::loadaddr, 0, symRef);73427343node = TR::Node::createWithSymRef(TR::call, 2, 2, value, statics, volatileLongSymRef);7344}7345else7346{7347node = TR::Node::createStore(symRef, value);7348}73497350if (symbol->isPrivate() && _classInfo && comp()->getNeedsClassLookahead() && !symbol->isVolatile())7351{7352if (!_classInfo->getFieldInfo())7353performClassLookahead(_classInfo);73547355// findFieldInfo will update node, if node is array shadow, as it set canBeArrayShadow=true7356// For normal static findFieldInfo will not update node, it can't be arrayShadow store7357// So set canBeArrayShadow false here7358//7359TR_PersistentFieldInfo * fieldInfo = _classInfo->getFieldInfo() ? _classInfo->getFieldInfo()->findFieldInfo(comp(), node, false) : NULL;7360//traceMsg(comp(), "Field %p info %p\n", node, fieldInfo);7361if (storeCanBeRemovedForUnreadField(fieldInfo, value) &&7362performTransformation(comp(), "O^O CLASS LOOKAHEAD: Can skip store to static (that is never read) storing value %p based on class file examination\n", value))7363{7364//int32_t length;7365//char *sig = TR_ClassLookahead::getFieldSignature(comp(), symbol, symRef, length);7366//fprintf(stderr, "Skipping store for field %s in %s\n", sig, comp()->signature());7367//fflush(stderr);7368int32_t numChildren = node->getNumChildren();7369int32_t i = 0;7370while (i < numChildren)7371{7372genTreeTop(node->getChild(i));7373node->getChild(i)->decReferenceCount();7374i++;7375}7376return;7377}7378}73797380if (symRef->isUnresolved())7381node = genResolveCheck(node);73827383handleSideEffect(node);73847385genTreeTop(node);7386}73877388void7389TR_J9ByteCodeIlGenerator::storeDualAuto(TR::Node * storeValue, int32_t slot)7390{7391TR_ASSERT(storeValue->isDualHigh() || storeValue->isSelectHigh(), "Coerced types only happen when a dual or select operator is generated.");73927393// type may need to be coerced from TR::Address into the type of the value being stored7394TR::DataType type = storeValue->getDataType();73957396// generate the two stores for the storeValue and its adjunct.7397TR::Node* adjunctValue = storeValue->getChild(2);7398if (storeValue->isSelectHigh())7399{7400adjunctValue = adjunctValue->getFirstChild();7401}7402push(storeValue);7403storeAuto(type, slot);7404push(adjunctValue);7405storeAuto(type, slot, true);7406return;7407}74087409void7410TR_J9ByteCodeIlGenerator::storeAuto(TR::DataType type, int32_t slot, bool isAdjunct)7411{7412TR::Node* storeValue = pop();74137414TR::SymbolReference * symRef;74157416if (storeValue->getDataType() != type && type == TR::Address)7417{7418// this presently happens only when an operator returning Quad was coerced from7419// a TR::Address type into a TR_SInt64 type, and a "dual operator" was created.7420// store the dual symbol7421storeDualAuto(storeValue, slot);7422return;7423}74247425symRef = symRefTab()->findOrCreateAutoSymbol(_methodSymbol, slot, type, true, false, true, isAdjunct);7426if (storeValue->isDualHigh() || storeValue->isSelectHigh() || isAdjunct)7427symRef->setIsDual();74287429bool isStatic = _methodSymbol->isStatic();74307431//Partial Inlining: if we store into a parameter we need to create a temporary for the callback. We need to create the store for the temp in the first block.74327433int32_t numParmSlots = _methodSymbol->getNumParameterSlots();74347435if(_blocksToInline)7436{7437if (slot < numParmSlots)7438{7439//printf("Walker: (partial)storeAuto: storing into a Parameter. numParmSlots = %d isStatic = %d slot = %d\n",numParmSlots,isStatic,slot);7440//Need to create a temporary and use it in the callback7441TR::Block *firstBlock = blocks(0);74427443TR::SymbolReference *tempRef = symRefTab()->createTemporary(_methodSymbol,type);7444TR::Node *loadNode = TR::Node::createWithSymRef(comp()->il.opCodeForDirectLoad(type),0,symRef);7445TR::Node *ttNode = TR::Node::createStore(tempRef, loadNode);7446blocks(0)->prepend(TR::TreeTop::create(_compilation, ttNode));74477448_blocksToInline->hasGeneratedRestartTree() ? patchPartialInliningCallBack(slot,symRef,tempRef,_blocksToInline->getGeneratedRestartTree()) : addTempForPartialInliningCallBack(slot,tempRef,numParmSlots);7449}7450}7451// If there's a store into the receiver of a synchronized method then we7452// would need to go to some effort to make sure we unlock the right object7453// on exit, and it's just not worth it because nobody actually does this.7454//7455if (slot == 0 && _methodSymbol->isSynchronised() && !isStatic)7456{7457comp()->failCompilation<TR::ILGenFailure>("store to this in sync method");7458}74597460TR::Node * node = TR::Node::createStore(symRef, storeValue);74617462handleSideEffect(node);74637464genTreeTop(node);74657466// If there's a store into the receiver of a synchronized method then we have to save the receive into a7467// temp and use the temporary on the monitorexit7468//7469if (slot == 0 && _methodSymbol->isSynchronised() && !isStatic && !_methodSymbol->getSyncObjectTemp()) // RTSJ support7470{7471_methodSymbol->setSyncObjectTemp(symRefTab()->createTemporary(_methodSymbol, TR::Address));7472ListIterator<TR::Node> i(&_implicitMonitorExits);7473for (TR::Node * monexit = i.getFirst(); monexit; monexit = i.getNext())7474{7475TR::Node *newLoad = TR::Node::createLoad(_methodSymbol->getSyncObjectTemp());7476monexit->setChild(0, newLoad);7477}7478}74797480// If there's a store into the receiver of Object.<init> then save the receiver into a temporary and use7481// the temporary as the parameter of the call to jitCheckIfFinalize7482//7483if (slot == 0 &&7484_methodSymbol->getResolvedMethod()->isObjectConstructor() &&7485!_methodSymbol->getThisTempForObjectCtor())7486{7487TR::SymbolReference *tempSymRef = symRefTab()->createTemporary(_methodSymbol, TR::Address);7488///traceMsg(comp(), "created tempSymRef = %d\n", tempSymRef->getReferenceNumber());7489_methodSymbol->setThisTempForObjectCtor(tempSymRef);7490// iterate through other returns in this method to make sure all the calls to jitCheckIfFinalizeObject7491// use this particular symref7492//7493ListIterator<TR::Node> i(&_finalizeCallsBeforeReturns);7494for (TR::Node *finalize = i.getFirst(); finalize; finalize = i.getNext())7495{7496TR::Node *receiverArg = finalize->getFirstChild();7497if (receiverArg->getOpCode().hasSymbolReference() &&7498receiverArg->getSymbolReference() != tempSymRef)7499{7500receiverArg->decReferenceCount();7501receiverArg = TR::Node::createLoad(tempSymRef);7502finalize->setAndIncChild(0, receiverArg);7503}7504}7505}7506}75077508void7509TR_J9ByteCodeIlGenerator::storeArrayElement(TR::DataType dataType, TR::ILOpCodes nodeop, bool checks)7510{7511TR::Node * value = pop();75127513handlePendingPushSaveSideEffects(value);75147515// Value types prototype for flattened array elements does not yet support7516// GC policies that allow arraylets. If arraylets are required, assume7517// we won't have flattening, so no call to flattenable array element access7518// helper is needed.7519//7520if (TR::Compiler->om.areValueTypesEnabled() && !TR::Compiler->om.canGenerateArraylets() && dataType == TR::Address)7521{7522TR::Node* elementIndex = pop();7523TR::Node* arrayBaseAddress = pop();7524if (!arrayBaseAddress->isNonNull())7525{7526auto* nullchk = TR::Node::create(TR::PassThrough, 1, arrayBaseAddress);7527nullchk = genNullCheck(nullchk);7528genTreeTop(nullchk);7529}7530auto* helperSymRef = comp()->getSymRefTab()->findOrCreateStoreFlattenableArrayElementSymbolRef();7531TR::TreeTop *storeHelperCallTT = genTreeTop(TR::Node::createWithSymRef(TR::call, 3, 3, value, elementIndex, arrayBaseAddress, helperSymRef));75327533const char *counterName = TR::DebugCounter::debugCounterName(comp(), "vt-helper/generated/aastore/(%s)/bc=%d",7534comp()->signature(), currentByteCodeIndex());7535TR::DebugCounter::prependDebugCounter(comp(), counterName, storeHelperCallTT);75367537return;7538}75397540bool genSpineChecks = comp()->requiresSpineChecks();75417542_suppressSpineChecks = false;75437544calculateArrayElementAddress(dataType, true);75457546TR::Node * arrayBaseAddress = pop();7547bool usedArrayBaseAddress = false;7548TR::Node * elementAddress = pop();75497550TR::SymbolReference * symRef = symRefTab()->findOrCreateArrayShadowSymbolRef(dataType, NULL);7551bool generateWriteBarrier = (dataType == TR::Address);75527553TR::Node * storeNode, * resultNode;7554if (generateWriteBarrier)7555{7556storeNode = resultNode = TR::Node::createWithSymRef(TR::awrtbari, 3, 3, elementAddress, value, arrayBaseAddress, symRef);7557usedArrayBaseAddress = true;7558}7559else7560{7561storeNode = resultNode = TR::Node::createWithSymRef(nodeop, 2, 2, elementAddress, value, symRef);7562}75637564// For hybrid arrays, an incomplete check node may have been pushed on the stack.7565// It may not exist if the bound and spine check have been skipped.7566//7567TR::Node *checkNode = NULL;75687569if (genSpineChecks && !_stack->isEmpty())7570{7571if (_stack->top()->getOpCode().isSpineCheck())7572{7573checkNode = pop();7574usedArrayBaseAddress = true;7575}7576}75777578if (dataType == TR::Address)7579{7580bool canSkipThisArrayStoreCheck = _methodSymbol->skipArrayStoreChecks() && checks; // transformed java/lang/unsafe calls don't require checks;7581if (!canSkipThisArrayStoreCheck && _classInfo && value->getOpCodeValue() == TR::New)7582{7583if (!_classInfo->getFieldInfo())7584performClassLookahead(_classInfo);75857586TR_PersistentFieldInfo * fieldInfo = _classInfo->getFieldInfo() ? _classInfo->getFieldInfo()->findFieldInfo(comp(), arrayBaseAddress, false) : NULL;7587TR_PersistentFieldInfo * arrayFieldInfo = fieldInfo ? fieldInfo->asPersistentArrayFieldInfo() : 0;7588if (arrayFieldInfo && arrayFieldInfo->isTypeInfoValid())7589{7590int32_t len;7591const char * s = value->getFirstChild()->getSymbolReference()->getTypeSignature(len);7592if (arrayFieldInfo->getNumChars() == len && !memcmp(s, arrayFieldInfo->getClassPointer(), len))7593{7594if (performTransformation(comp(), "O^O CLASS LOOKAHEAD: Can skip array store check for value %p using array object %p which has type %s based on class file examination\n", value, arrayBaseAddress, s))7595canSkipThisArrayStoreCheck = true;7596}7597}7598}75997600if (!canSkipThisArrayStoreCheck)7601{7602symRef = symRefTab()->findOrCreateTypeCheckArrayStoreSymbolRef(_methodSymbol);7603TR_ASSERT(generateWriteBarrier,"TR::ArrayStoreCHK needs write barrier support.");7604if (generateWriteBarrier)7605resultNode = TR::Node::createWithRoomForThree(TR::ArrayStoreCHK, storeNode, 0, symRef);7606}7607}76087609if (!usedArrayBaseAddress)7610removeIfNotOnStack(arrayBaseAddress);76117612handleSideEffect(storeNode);76137614// if a compressedRefs anchor has to be7615// generated, dont do anything for if7616// the result is just the store7617//7618bool genTranslateTT = (comp()->useCompressedPointers() && (dataType == TR::Address));76197620// If the store is hung off the bound or spine check then do not anchor it7621// under its own treetop.7622//7623if (checkNode)7624{7625if (resultNode->getOpCodeValue() == TR::ArrayStoreCHK || (storeNode->getOpCode().isWrtBar() && !genTranslateTT))7626{7627// Anchor the array store check or the write barrier under its own treetop.7628//7629genTreeTop(resultNode);7630}7631}7632else7633{7634if (!((genTranslateTT) && resultNode->getOpCode().isStore()))7635genTreeTop(resultNode);7636}76377638if (genTranslateTT)7639{7640TR::Node *newValue = genCompressedRefs(storeNode, true, -1);7641if (newValue)7642{7643storeNode->getSecondChild()->decReferenceCount();7644storeNode->setAndIncChild(1, newValue);7645}7646}76477648if (checkNode)7649{7650if (checkNode->getOpCode().isBndCheck())7651{7652TR_ASSERT(checkNode->getOpCodeValue() == TR::BNDCHKwithSpineCHK, "unexpected check node");76537654// Re-arrange children now that element address and base address7655// are known.7656//7657checkNode->setChild(2, checkNode->getChild(0)); // arraylength7658checkNode->setChild(3, checkNode->getChild(1)); // index7659}7660else7661{7662TR_ASSERT(checkNode->getOpCodeValue() == TR::SpineCHK, "unexpected check node");7663checkNode->setChild(2, checkNode->getChild(0)); // index7664}76657666// The store node cannot, in general, be hung from the check node7667// because the resulting tree may have multiple side effects. For example,7668// a BNDCHKwithSpineCHK node with an ArrayStoreCHK beneath it. So,7669// the tree is created with the array element address instead. This7670// is sub-optimal in the sense that the destination address is always7671// evaluated into a register first, thereby bypassing any direct memory7672// opportunities.7673//76747675if (storeNode->getOpCode().isWrtBar())7676checkNode->setAndIncChild(0, elementAddress); // iwrtbar7677else7678{7679checkNode->setSpineCheckWithArrayElementChild(true);7680checkNode->setAndIncChild(0, storeNode); // primitive store7681}7682checkNode->setAndIncChild(1, arrayBaseAddress); // base array7683}76847685}76867687//----------------------------------------------7688// gen switch7689//----------------------------------------------76907691int32_t7692TR_J9ByteCodeIlGenerator::genLookupSwitch()7693{7694int32_t i = 1;7695while ((intptr_t)&_code[_bcIndex+i] & 3) ++i; // 4 byte align76967697int32_t bcIndex = _bcIndex + i;7698int32_t defaultTarget = nextSwitchValue(bcIndex) + _bcIndex;7699int32_t tableSize = nextSwitchValue(bcIndex);77007701TR::Node * first = pop();77027703if (tableSize == 0)7704{7705first->incReferenceCount();7706first->recursivelyDecReferenceCount();7707return genGoto(defaultTarget);7708}77097710handlePendingPushSaveSideEffects(first);77117712bool needAsyncCheck = defaultTarget <= _bcIndex ? true : false;7713TR::Node * caseNode = TR::Node::createCase( 0, genTarget(defaultTarget));7714TR::Node * node = TR::Node::create(TR::lookup, tableSize + 2, first, caseNode);77157716for (i = 0; i < tableSize; ++i)7717{7718int32_t intMatch = nextSwitchValue(bcIndex);7719int32_t target = nextSwitchValue(bcIndex) + _bcIndex;7720if (target <= _bcIndex)7721needAsyncCheck = true;7722node->setAndIncChild(i + 2, TR::Node::createCase( 0, genTarget(target), intMatch));7723}77247725if (needAsyncCheck)7726genAsyncCheck();7727genTreeTop(node);7728return findNextByteCodeToGen();7729}77307731int32_t7732TR_J9ByteCodeIlGenerator::genTableSwitch()7733{7734int32_t i = 1;7735while ((intptr_t)&_code[_bcIndex+i] & 3) ++i; // 4 byte align77367737int32_t bcIndex = _bcIndex + i;7738int32_t defaultTarget = nextSwitchValue(bcIndex) + _bcIndex;7739int32_t low = nextSwitchValue(bcIndex);7740int32_t high = nextSwitchValue(bcIndex);7741if (low != 0)7742{7743loadConstant(TR::iconst, low);7744genBinary(TR::isub);7745high = high - low;7746}77477748TR::Node * first = pop();77497750handlePendingPushSaveSideEffects(first);77517752bool needAsyncCheck = defaultTarget <= _bcIndex ? true : false;7753TR::Node * caseNode = TR::Node::createCase(0, genTarget(defaultTarget));7754TR::Node * node = TR::Node::create(TR::table, high + 3, first, caseNode);77557756TR_Array<TR::Node *> caseTargets(trMemory(), _maxByteCodeIndex + 1, true, stackAlloc);7757for (i = 0; i < high + 1; ++i)7758{7759int32_t targetIndex = nextSwitchValue(bcIndex) + _bcIndex;7760if (targetIndex <= _bcIndex)7761needAsyncCheck = true;7762if (!caseTargets[targetIndex])7763caseTargets[targetIndex] = TR::Node::createCase(0, genTarget(targetIndex));7764node->setAndIncChild(i + 2, caseTargets[targetIndex]);7765}77667767if (needAsyncCheck)7768genAsyncCheck();7769genTreeTop(node);7770return findNextByteCodeToGen();7771}77727773//----------------------------------------------7774// gen throw7775//----------------------------------------------77767777int32_t7778TR_J9ByteCodeIlGenerator::genAThrow()7779{7780TR::Node * node = TR::Node::createWithSymRef(TR::athrow, 1, 1, pop(), symRefTab()->findOrCreateAThrowSymbolRef(_methodSymbol));77817782bool canSkipNullCheck = node->getFirstChild()->isNonNull();7783if (!canSkipNullCheck && _classInfo)7784{7785if (!_classInfo->getFieldInfo())7786performClassLookahead(_classInfo);7787TR::Node * thisObject = node->getFirstChild();7788TR_PersistentFieldInfo * fieldInfo = _classInfo->getFieldInfo() ? _classInfo->getFieldInfo()->findFieldInfo(comp(), thisObject, false) : NULL;7789if (fieldInfo && fieldInfo->isTypeInfoValid())7790{7791if (performTransformation(comp(), "O^O CLASS LOOKAHEAD: Can skip null check at exception throw %p based on class file examination\n", thisObject))7792canSkipNullCheck = true;7793}7794}77957796if (comp()->getOption(TR_EnableThisLiveRangeExtension))7797{7798if (!_methodSymbol->isStatic() &&7799(!fej9()->isClassFinal(_methodSymbol->getResolvedMethod()->containingClass()) ||7800fej9()->hasFinalizer(_methodSymbol->getResolvedMethod()->containingClass())))7801{7802loadAuto(TR::Address, 0);7803TR::SymbolReference *tempSymRef = symRefTab()->findOrCreateThisRangeExtensionSymRef(comp()->getMethodSymbol());7804genTreeTop(TR::Node::createStore(tempSymRef, pop()));7805}7806}78077808if (!canSkipNullCheck)7809node = genNullCheck(node);78107811genTreeTop(node);78127813discardEntireStack();78147815return findNextByteCodeToGen();7816}78177818// genFlush: provide a store barrier for weakly consistent memory system//7819//7820void TR_J9ByteCodeIlGenerator::genFlush(int32_t nargs)7821{7822if (cg()->getEnforceStoreOrder())7823{7824TR::Node *newNode = node(_stack->topIndex() - nargs);7825TR::Node *flushNode = TR::Node::createAllocationFence(NULL, newNode);78267827genTreeTop(flushNode);7828}7829}78307831void TR_J9ByteCodeIlGenerator::genFullFence(TR::Node *node)7832{7833TR::Node *fullFenceNode = TR::Node::createWithSymRef(node, TR::fullFence, 0, node->getSymbolReference());7834fullFenceNode->setOmitSync(true);7835genTreeTop(fullFenceNode);7836}783778387839void TR_J9ByteCodeIlGenerator::performClassLookahead(TR_PersistentClassInfo *classInfo)7840{7841#if defined(J9VM_OPT_JITSERVER)7842// Do not perform class lookahead in server mode7843if (comp()->isOutOfProcessCompilation())7844return;7845#endif7846// Do not perform class lookahead when peeking (including recursive class lookahead)7847//7848if (comp()->isPeekingMethod())7849return;7850// Do not perform class lookahead if classes can be redefined7851if (comp()->getOption(TR_EnableHCR))7852return;78537854if (comp()->compileRelocatableCode() && !comp()->getOption(TR_UseSymbolValidationManager))7855return;78567857_classLookaheadSymRefTab = new (trStackMemory())TR::SymbolReferenceTable(method()->maxBytecodeIndex(), comp());78587859TR::SymbolReferenceTable *callerCurrentSymRefTab = comp()->getCurrentSymRefTab();7860comp()->setCurrentSymRefTab(_classLookaheadSymRefTab);7861TR_ClassLookahead classLookahead(classInfo, fej9(), comp(), _classLookaheadSymRefTab);7862classLookahead.perform();7863comp()->setCurrentSymRefTab(callerCurrentSymRefTab);7864}786578667867