Path: blob/master/runtime/compiler/optimizer/J9RecognizedCallTransformer.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2017, 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 "optimizer/RecognizedCallTransformer.hpp"2324#include "compile/ResolvedMethod.hpp"25#include "env/CompilerEnv.hpp"26#include "env/VMJ9.h"27#include "env/jittypes.h"28#include "il/Block.hpp"29#include "il/Node.hpp"30#include "il/Node_inlines.hpp"31#include "il/StaticSymbol.hpp"32#include "il/TreeTop.hpp"33#include "il/TreeTop_inlines.hpp"34#include "il/ILOpCodes.hpp"35#include "il/ILOps.hpp"36#include "ilgen/IlGenRequest.hpp"37#include "ilgen/IlGeneratorMethodDetails.hpp"38#include "ilgen/IlGeneratorMethodDetails_inlines.hpp"39#include "optimizer/CallInfo.hpp"40#include "optimizer/IdiomRecognitionUtils.hpp"41#include "optimizer/Structure.hpp"42#include "codegen/CodeGenerator.hpp"43#include "optimizer/TransformUtil.hpp"44#include "env/j9method.h"45#include "optimizer/Optimization_inlines.hpp"4647void J9::RecognizedCallTransformer::processIntrinsicFunction(TR::TreeTop* treetop, TR::Node* node, TR::ILOpCodes opcode)48{49TR::Node::recreate(node, opcode);50}5152void J9::RecognizedCallTransformer::processConvertingUnaryIntrinsicFunction(TR::TreeTop* treetop, TR::Node* node, TR::ILOpCodes argConvertOpcode, TR::ILOpCodes opcode, TR::ILOpCodes resultConvertOpcode)53{54TR::Node* actualArg = TR::Node::create(argConvertOpcode, 1, node->getFirstChild());55TR::Node* actualResult = TR::Node::create(opcode, 1, actualArg);5657TR::Node::recreate(node, resultConvertOpcode);58node->getFirstChild()->decReferenceCount();59node->setAndIncChild(0, actualResult);60}6162void J9::RecognizedCallTransformer::process_java_lang_Class_IsAssignableFrom(TR::TreeTop* treetop, TR::Node* node)63{64auto toClass = node->getChild(0);65auto fromClass = node->getChild(1);66auto nullchk = comp()->getSymRefTab()->findOrCreateNullCheckSymbolRef(comp()->getMethodSymbol());67treetop->insertBefore(TR::TreeTop::create(comp(), TR::Node::createWithSymRef(TR::NULLCHK, 1, 1, TR::Node::create(node, TR::PassThrough, 1, toClass), nullchk)));68treetop->insertBefore(TR::TreeTop::create(comp(), TR::Node::createWithSymRef(TR::NULLCHK, 1, 1, TR::Node::create(node, TR::PassThrough, 1, fromClass), nullchk)));6970TR::Node::recreate(treetop->getNode(), TR::treetop);71node->setSymbolReference(comp()->getSymRefTab()->findOrCreateRuntimeHelper(TR_checkAssignable));72node->setAndIncChild(0, TR::Node::createWithSymRef(TR::aloadi, 1, 1, toClass, comp()->getSymRefTab()->findOrCreateClassFromJavaLangClassSymbolRef()));73node->setAndIncChild(1, TR::Node::createWithSymRef(TR::aloadi, 1, 1, fromClass, comp()->getSymRefTab()->findOrCreateClassFromJavaLangClassSymbolRef()));74node->swapChildren();7576toClass->recursivelyDecReferenceCount();77fromClass->recursivelyDecReferenceCount();78}7980// This methods inlines a call node that calls StringCoding.encodeASCII into an if-diamond. The forward path of the81// if-diamond inlines the call using a compiler intrinsic and the fallback path reverts back to calling the method traditionally.82void J9::RecognizedCallTransformer::process_java_lang_StringCoding_encodeASCII(TR::TreeTop* treetop, TR::Node* node)83{84TR_J9VMBase *fej9 = static_cast<TR_J9VMBase*>(comp()->fe());85TR_OpaqueClassBlock *stringClass = comp()->getStringClassPointer();86if (!stringClass || !fej9->getByteArrayClass())87{88return;89}90uint32_t *latin1FieldAddress = (uint32_t *)fej9->getStaticFieldAddress(stringClass, (unsigned char *) "LATIN1", 6, (unsigned char *)"B", 1);91TR::CFG *cfg = comp()->getFlowGraph();9293TR::Node *coderNode = node->getChild(0);94TR::Node *sourceArrayNode = node->getChild(1);9596// Anchor the source array node as we need it in the fallthrough block.97anchorNode(sourceArrayNode, treetop);9899// Now generate the ificmpne tree and insert it before the original call tree.100// Note that *latin1FieldAddress will be correct for AOT compilations as well because String.LATIN1 is a final static field with101// a constant initializer. This means its value is determined by the ROM class of String, and therefore when the String class chain validation succeeds102// on AOT load, the value is guaranteed to be the same as the one we see during AOT compilation.103TR::Node *constNode = TR::Node::iconst(node, ((TR_J9VM *)fej9)->dereferenceStaticFinalAddress(latin1FieldAddress, TR::Int32).dataInt32Bit);104TR::Node *ifCmpNode = TR::Node::createif(TR::ificmpne, coderNode, constNode);105TR::TreeTop *ifCmpTreeTop = TR::TreeTop::create(comp(), treetop->getPrevTreeTop(), ifCmpNode);106107// Split the current block right before the call (or after the ificmpne).108TR::Block *ifCmpBlock = ifCmpTreeTop->getEnclosingBlock();109TR::Block *fallbackPathBlock = ifCmpBlock->split(treetop, cfg, true /* fixUpCommoning */, true /* copyExceptionSuccessors */);110// Then split again to create the tail block111TR::Block *tailBlock = fallbackPathBlock->split(treetop->getNextTreeTop(), cfg, true /* fixUpCommoning */, true /* copyExceptionSuccessors */);112113// Now we have the originalBlock, the fallback block and the merge block (tailBlock). The call result will be an astore.114// If the nodes in the above blocks were uncommoned as expected, then the treetop after the call node should be an astore to a temp slot.115// So assert that it is, and then grab a reference to the temp slot so we can store to it ourselves in the forward path.116// Note that we can rely on the call result having been used in a later tree since encodeASCII represents a private method whose call sites we can inspect117// and because this transformation happens very early as part of ilgen opts118TR::Node *resultStoreNode = treetop->getNextTreeTop()->getNode();119TR::SymbolReference *tempSlotForCallResult = NULL;120TR_ASSERT_FATAL(resultStoreNode, "Treetop after call is not an astore");121TR_ASSERT_FATAL(resultStoreNode->getOpCode().getOpCodeValue() == TR::astore, "Treetop after call must be an astore to a temp!");122tempSlotForCallResult = resultStoreNode->getSymbolReference();123TR_ASSERT_FATAL(tempSlotForCallResult, "Symbol reference for store node can't be null\n");124TR_ASSERT_FATAL(resultStoreNode->getChild(0) == node, "The value stored must be the call result");125126// Ready to create our fallthrough block now. Connect it to ifCmpTreeTop, and then split it with nodes commoned.127int32_t byteArrayType = fej9->getNewArrayTypeFromClass(fej9->getByteArrayClass());128129// Create a new arraylength node.130sourceArrayNode = node->getChild(1)->duplicateTree();131TR::Node *lenNode = TR::Node::create(node, TR::arraylength, 1, sourceArrayNode);132133// Create the destination array134TR::Node *destinationArrayNode = TR::Node::createWithSymRef(node, TR::newarray, 2, comp()->getSymRefTab()->findOrCreateNewArraySymbolRef(node->getSymbolReference()->getOwningMethodSymbol(comp())));135destinationArrayNode->setAndIncChild(0, lenNode);136destinationArrayNode->setAndIncChild(1, TR::Node::iconst(byteArrayType));137TR::TreeTop *destinationArrayTreeTop = TR::TreeTop::create(comp(), TR::Node::create(node, TR::treetop, 1, destinationArrayNode));138ifCmpTreeTop->insertAfter(destinationArrayTreeTop);139destinationArrayNode->setCanSkipZeroInitialization(true);140destinationArrayNode->setIsNonNull(true);141142// We now have the length node, and also the destination array. Now we create an encodeASCIISymbol node to do the encoding operation.143/*144// tree looks as follows:145// call encodeASCIISymbol146// input ptr147// output ptr148// input length (in elements)149*/150151TR::SymbolReference *methodSymRef = comp()->getSymRefTab()->findOrCreateEncodeASCIISymbolRef();152TR::Node *encodeASCIINode = TR::Node::createWithSymRef(TR::call, 3, methodSymRef);153154TR::Node *newInputNode = NULL;155TR::Node *arrayHeaderSizeNode = NULL;156TR::Node *newOutputNode = NULL;157158if (comp()->target().is64Bit())159{160newInputNode = TR::Node::create(sourceArrayNode, TR::aladd, 2);161newOutputNode = TR::Node::create(destinationArrayNode, TR::aladd, 2);162arrayHeaderSizeNode = TR::Node::lconst((int64_t)TR::Compiler->om.contiguousArrayHeaderSizeInBytes());163}164else165{166newInputNode = TR::Node::create(sourceArrayNode, TR::aiadd, 2);167newOutputNode = TR::Node::create(destinationArrayNode, TR::aiadd, 2);168arrayHeaderSizeNode = TR::Node::iconst((int32_t)TR::Compiler->om.contiguousArrayHeaderSizeInBytes());169}170171newInputNode->setAndIncChild(0, sourceArrayNode);172newInputNode->setAndIncChild(1, arrayHeaderSizeNode);173encodeASCIINode->setAndIncChild(0, newInputNode);174175newOutputNode->setAndIncChild(0, destinationArrayNode);176newOutputNode->setAndIncChild(1, arrayHeaderSizeNode);177encodeASCIINode->setAndIncChild(1, newOutputNode);178179encodeASCIINode->setAndIncChild(2, lenNode);180181TR::TreeTop *encodeASCIITreeTop = TR::TreeTop::create(comp(), TR::Node::create(node, TR::treetop, 1, encodeASCIINode));182destinationArrayTreeTop->insertAfter(encodeASCIITreeTop);183184TR::Node *storeNode = TR::Node::createWithSymRef(node, TR::astore, 1, destinationArrayNode, tempSlotForCallResult);185TR::TreeTop *storeNodeTreeTop = TR::TreeTop::create(comp(), encodeASCIITreeTop, storeNode);186187// Now split starting from destinationArrayTreeTop and uncommon the nodes..188TR::Block *fallthroughBlock = destinationArrayTreeTop->getEnclosingBlock()->split(destinationArrayTreeTop, cfg, true /* fixUpCommoning */, true /* copyExceptionSuccessors */);189190// Now create a node to go to the merge (i.e. tail) block.191TR::Node *gotoNode = TR::Node::create(node, TR::Goto);192TR::TreeTop *gotoTree = TR::TreeTop::create(comp(), gotoNode, NULL, NULL);193gotoNode->setBranchDestination(tailBlock->getEntry());194fallthroughBlock->getExit()->insertBefore(gotoTree);195196// Now we have fallthrough block, fallback block and tail/merge block. Let's set the ifcmp's destination to the fallback block, and update the CFG as well.197ifCmpNode->setBranchDestination(fallbackPathBlock->getEntry());198cfg->addEdge(ifCmpTreeTop->getEnclosingBlock(), fallbackPathBlock);199cfg->addEdge(fallthroughBlock, tailBlock);200cfg->removeEdge(fallthroughBlock, fallbackPathBlock);201}202203void J9::RecognizedCallTransformer::process_java_lang_StringUTF16_toBytes(TR::TreeTop* treetop, TR::Node* node)204{205TR_J9VMBase* fej9 = static_cast<TR_J9VMBase*>(comp()->fe());206207TR::Node* valueNode = node->getChild(0);208TR::Node* offNode = node->getChild(1);209TR::Node* lenNode = node->getChild(2);210211anchorAllChildren(node, treetop);212prepareToReplaceNode(node);213214int32_t byteArrayType = fej9->getNewArrayTypeFromClass(fej9->getByteArrayClass());215216TR::Node::recreateWithoutProperties(node, TR::newarray, 2,217TR::Node::create(TR::ishl, 2,218lenNode,219TR::Node::iconst(1)),220TR::Node::iconst(byteArrayType),221222getSymRefTab()->findOrCreateNewArraySymbolRef(node->getSymbolReference()->getOwningMethodSymbol(comp())));223224TR::Node* newByteArrayNode = node;225newByteArrayNode->setCanSkipZeroInitialization(true);226newByteArrayNode->setIsNonNull(true);227228TR::Node* newCallNode = TR::Node::createWithSymRef(node, TR::call, 5,229getSymRefTab()->methodSymRefFromName(comp()->getMethodSymbol(), "java/lang/String", "decompressedArrayCopy", "([CI[BII)V", TR::MethodSymbol::Static));230newCallNode->setAndIncChild(0, valueNode);231newCallNode->setAndIncChild(1, offNode);232newCallNode->setAndIncChild(2, newByteArrayNode);233newCallNode->setAndIncChild(3, TR::Node::iconst(0));234newCallNode->setAndIncChild(4, lenNode);235236treetop->insertAfter(TR::TreeTop::create(comp(), TR::Node::create(node, TR::treetop, 1, newCallNode)));237}238239void J9::RecognizedCallTransformer::process_java_lang_StrictMath_and_Math_sqrt(TR::TreeTop* treetop, TR::Node* node)240{241TR::Node* valueNode = node->getLastChild();242243anchorAllChildren(node, treetop);244prepareToReplaceNode(node);245246TR::Node::recreate(node, TR::dsqrt);247node->setNumChildren(1);248node->setAndIncChild(0, valueNode);249250TR::TransformUtil::removeTree(comp(), treetop);251}252/*253Transform an Unsafe atomic call to diamonds with equivalent semantics254255yes256isObjectNull ------------------------------------------>257| |258| no |259| yes |260isNotLowTagged ---------------------------------------->261| |262| no |263| no |264isFinal ----------------------> |265| | |266| yes | |267| | |268call the calculate address calculate address269original method for static field for instance field270| | and absolute address271| | |272| |________________________|273| |274| xcall atomic method helper275| |276|_____________________________________|277|278program after the original call279280Block before the transformation: ===>281282start Block_A283...284xcall Unsafe.xxx285...286end Block_A287288Blocks after the transformation: ===>289290start Block_A291...292ifacmpeq -> <Block_E>293object294aconst null295end Block_A296297start Block_B298iflcmpne -> <Block_E>299land300lload <offset>301lconst J9_SUN_STATIC_FIELD_OFFSET_TAG302lconst J9_SUN_STATIC_FIELD_OFFSET_TAG303end Block_B304305start Block_C306iflcmpeq -> <Block_F>307land308lload <offset>309lconst J9_SUN_FINAL_FIELD_OFFSET_TAG310lconst J9_SUN_FINAL_FIELD_OFFSET_TAG311end Block_C312313start Block_D314astore <object>315aloadi ramStaticsFromClass316...317lstore <offset>318land319lload <offset>320lconst ~J9_SUN_FIELD_OFFSET_MASK321end Block_D322323start Block_E324xcall atomic method helper325aladd326aload <object>327lload <offset>328xload value329end Block_E330331...332333start Block_F334call jitReportFinalFieldModified335go to <Block_E>336end Block_F337*/338void J9::RecognizedCallTransformer::processUnsafeAtomicCall(TR::TreeTop* treetop, TR::SymbolReferenceTable::CommonNonhelperSymbol helper, bool needsNullCheck)339{340bool enableTrace = trace();341bool isNotStaticField = !strncmp(comp()->getCurrentMethod()->classNameChars(), "java/util/concurrent/atomic/", strlen("java/util/concurrent/atomic/"));342bool fixupCommoning = true;343TR::Node* unsafeCall = treetop->getNode()->getFirstChild();344TR::Node* objectNode = unsafeCall->getChild(1);345TR::Node* offsetNode = unsafeCall->getChild(2);346TR::Node* address = NULL;347348// Preserve null check on the unsafe object349if (treetop->getNode()->getOpCode().isNullCheck())350{351TR::Node *passthrough = TR::Node::create(unsafeCall, TR::PassThrough, 1);352passthrough->setAndIncChild(0, unsafeCall->getFirstChild());353TR::Node * checkNode = TR::Node::createWithSymRef(treetop->getNode(), TR::NULLCHK, 1, passthrough, treetop->getNode()->getSymbolReference());354treetop->insertBefore(TR::TreeTop::create(comp(), checkNode));355TR::Node::recreate(treetop->getNode(), TR::treetop);356if (enableTrace)357traceMsg(comp(), "Created node %p to preserve NULLCHK on unsafe call %p\n", checkNode, unsafeCall);358}359360if (isNotStaticField)361{362// It is safe to skip diamond, the address can be calculated directly via [object+offset]363address = comp()->target().is32Bit() ? TR::Node::create(TR::aiadd, 2, objectNode, TR::Node::create(TR::l2i, 1, offsetNode)) :364TR::Node::create(TR::aladd, 2, objectNode, offsetNode);365if (enableTrace)366traceMsg(comp(), "Field is not static, use the object and offset directly\n");367}368else369{370// Otherwise, the address is [object+offset] for non-static field,371// or [object's ramStaticsFromClass + (offset & ~mask)] for static field372373// Save all the children to temps before splitting the block374TR::TransformUtil::createTempsForCall(this, treetop);375376auto cfg = comp()->getMethodSymbol()->getFlowGraph();377objectNode = unsafeCall->getChild(1);378offsetNode = unsafeCall->getChild(2);379380// Null Check381if (needsNullCheck)382{383auto NULLCHKNode = TR::Node::createWithSymRef(unsafeCall, TR::NULLCHK, 1,384TR::Node::create(TR::PassThrough, 1, objectNode->duplicateTree()),385comp()->getSymRefTab()->findOrCreateNullCheckSymbolRef(comp()->getMethodSymbol()));386treetop->insertBefore(TR::TreeTop::create(comp(), NULLCHKNode));387if (enableTrace)388traceMsg(comp(), "Created NULLCHK tree %p on the first argument of Unsafe call\n", treetop->getPrevTreeTop());389}390391// Test if object is null392auto isObjectNullNode = TR::Node::createif(TR::ifacmpeq, objectNode->duplicateTree(), TR::Node::aconst(0), NULL);393auto isObjectNullTreeTop = TR::TreeTop::create(comp(), isObjectNullNode);394treetop->insertBefore(isObjectNullTreeTop);395treetop->getEnclosingBlock()->split(treetop, cfg, fixupCommoning);396397if (enableTrace)398traceMsg(comp(), "Created isObjectNull test node n%dn, non-null object will fall through to Block_%d\n", isObjectNullNode->getGlobalIndex(), treetop->getEnclosingBlock()->getNumber());399400// Test if low tag is set401auto isNotLowTaggedNode = TR::Node::createif(TR::iflcmpne,402TR::Node::create(TR::land, 2, offsetNode->duplicateTree(), TR::Node::lconst(J9_SUN_STATIC_FIELD_OFFSET_TAG)),403TR::Node::lconst(J9_SUN_STATIC_FIELD_OFFSET_TAG),404NULL);405auto isNotLowTaggedTreeTop = TR::TreeTop::create(comp(), isNotLowTaggedNode);406treetop->insertBefore(isNotLowTaggedTreeTop);407treetop->getEnclosingBlock()->split(treetop, cfg, fixupCommoning);408409if (enableTrace)410traceMsg(comp(), "Created isNotLowTagged test node n%dn, static field will fall through to Block_%d\n", isNotLowTaggedNode->getGlobalIndex(), treetop->getEnclosingBlock()->getNumber());411412static char *disableIllegalWriteReport = feGetEnv("TR_DisableIllegalWriteReport");413// Test if the call is a write to a static final field414if (!disableIllegalWriteReport415&& !comp()->getOption(TR_DisableGuardedStaticFinalFieldFolding)416&& TR_J9MethodBase::isUnsafePut(unsafeCall->getSymbol()->castToMethodSymbol()->getMandatoryRecognizedMethod()))417{418// If the field is static final419auto isFinalNode = TR::Node::createif(TR::iflcmpeq,420TR::Node::create(TR::land, 2, offsetNode->duplicateTree(), TR::Node::lconst(J9_SUN_FINAL_FIELD_OFFSET_TAG)),421TR::Node::lconst(J9_SUN_FINAL_FIELD_OFFSET_TAG),422NULL /*branchTarget*/);423auto isFinalTreeTop = TR::TreeTop::create(comp(), isFinalNode);424auto reportFinalFieldModification = TR::TransformUtil::generateReportFinalFieldModificationCallTree(comp(), objectNode->duplicateTree());425auto elseBlock = treetop->getEnclosingBlock();426TR::TransformUtil::createConditionalAlternatePath(comp(), isFinalTreeTop, reportFinalFieldModification, elseBlock, elseBlock, comp()->getMethodSymbol()->getFlowGraph(), true /*markCold*/);427if (enableTrace)428{429traceMsg(comp(), "Created isFinal test node n%dn, non-final-static field will fall through to Block_%d, final field goes to Block_%d\n",430isFinalNode->getGlobalIndex(), treetop->getEnclosingBlock()->getNumber(), reportFinalFieldModification->getEnclosingBlock()->getNumber());431}432TR::DebugCounter::prependDebugCounter(comp(),433TR::DebugCounter::debugCounterName(comp(),434"illegalWriteReport/atomic/(%s %s)",435comp()->signature(),436comp()->getHotnessName(comp()->getMethodHotness())),437reportFinalFieldModification->getNextTreeTop());438439}440441// Calculate static address442auto objectAdjustmentNode = TR::Node::createWithSymRef(TR::astore, 1, 1,443TR::Node::createWithSymRef(TR::aloadi, 1, 1,444TR::Node::createWithSymRef(TR::aloadi, 1, 1,445objectNode->duplicateTree(),446comp()->getSymRefTab()->findOrCreateClassFromJavaLangClassSymbolRef()),447comp()->getSymRefTab()->findOrCreateRamStaticsFromClassSymbolRef()),448objectNode->getSymbolReference());449auto offsetAdjustmentNode = TR::Node::createWithSymRef(TR::lstore, 1, 1,450TR::Node::create(TR::land, 2,451offsetNode->duplicateTree(),452TR::Node::lconst(~J9_SUN_FIELD_OFFSET_MASK)),453offsetNode->getSymbolReference());454455if (enableTrace)456traceMsg(comp(), "Created node n%dn and n%dn to adjust object and offset for static field\n", objectAdjustmentNode->getGlobalIndex(), offsetAdjustmentNode->getGlobalIndex());457458treetop->insertBefore(TR::TreeTop::create(comp(), objectAdjustmentNode));459treetop->insertBefore(TR::TreeTop::create(comp(), offsetAdjustmentNode));460treetop->getEnclosingBlock()->split(treetop, cfg, fixupCommoning);461462if (enableTrace)463traceMsg(comp(), "Block_%d contains call to atomic method helper, and is the target of isObjectNull and isNotLowTagged tests\n", treetop->getEnclosingBlock()->getNumber());464465// Setup CFG edges466isObjectNullNode->setBranchDestination(treetop->getEnclosingBlock()->getEntry());467cfg->addEdge(TR::CFGEdge::createEdge(isObjectNullTreeTop->getEnclosingBlock(), treetop->getEnclosingBlock(), comp()->trMemory()));468isNotLowTaggedNode->setBranchDestination(treetop->getEnclosingBlock()->getEntry());469cfg->addEdge(TR::CFGEdge::createEdge(isNotLowTaggedTreeTop->getEnclosingBlock(), treetop->getEnclosingBlock(), comp()->trMemory()));470address = comp()->target().is32Bit() ? TR::Node::create(TR::aiadd, 2, objectNode->duplicateTree(), TR::Node::create(TR::l2i, 1, offsetNode->duplicateTree())) :471TR::Node::create(TR::aladd, 2, objectNode->duplicateTree(), offsetNode->duplicateTree());472}473474// Transmute the unsafe call to a call to atomic method helper475unsafeCall->getChild(0)->recursivelyDecReferenceCount(); // replace unsafe object with the address476unsafeCall->setAndIncChild(0, address);477unsafeCall->removeChild(2); // remove offset node478unsafeCall->removeChild(1); // remove object node479unsafeCall->setSymbolReference(comp()->getSymRefTab()->findOrCreateCodeGenInlinedHelper(helper));480}481482#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)483484/** \brief485* Constructs signature strings for constructing methods representing computed calls486* from the signature of the original INL calls. Adapted from getSignatureForLinkToStatic487* in j9method.cpp488*489* \param extraParamsBefore490* the params to be prepended to the original signature491*492* \param extraParamsAfter493* the params to be appended to the original signature494*495* \param comp496* the current compilation497*498* \param origSignature499* the original signautre500*501* \param signatureLength502* the constructed signature length503*504* \return505* static char * the constructed signature506*/507508static char *509getSignatureForComputedCall(510const char * const extraParamsBefore,511const char * const extraParamsAfter,512TR::Compilation* comp,513const char * const origSignature,514int32_t &signatureLength)515{516const size_t extraParamsLength = strlen(extraParamsBefore) + strlen(extraParamsAfter);517518const int origSignatureLength = strlen(origSignature);519signatureLength = origSignatureLength + extraParamsLength;520521const int32_t signatureAllocSize = signatureLength + 28; // +1 for NULL terminator522char * computedCallSignature =523(char *)comp->trMemory()->allocateMemory(signatureAllocSize, heapAlloc);524525// Can't simply strchr() for ')' because that can appear within argument526// types, in particular within class names. It's necessary to parse the527// signature.528const char * const paramsStart = origSignature + 1;529const char * paramsEnd = paramsStart;530const char * previousParam = paramsEnd;531const char * returnType = NULL;532while (*paramsEnd != ')')533{534paramsEnd = nextSignatureArgument(paramsEnd);535if (!strncmp(paramsEnd, "Ljava/lang/invoke/MemberName;", 29)) // MemberName object must be discarded536{537returnType = nextSignatureArgument(paramsEnd) + 1;538break;539}540}541542if (!returnType) returnType = paramsEnd + 1;543const char * const returnTypeEnd = nextSignatureArgument(returnType);544545// Put together the new signature.546snprintf(547computedCallSignature,548signatureAllocSize,549"(%s%.*s%s)%.*s",550extraParamsBefore,551(int)(paramsEnd - paramsStart),552paramsStart,553extraParamsAfter,554(int)(returnTypeEnd - returnType),555returnType);556557return computedCallSignature;558}559560void J9::RecognizedCallTransformer::process_java_lang_invoke_MethodHandle_invokeBasic(TR::TreeTop * treetop, TR::Node* node)561{562TR_J9VMBase* fej9 = static_cast<TR_J9VMBase*>(comp()->fe());563TR::TransformUtil::separateNullCheck(comp(), treetop, true);564TR::Node * inlCallNode = node->duplicateTree(false);565TR::list<TR::SymbolReference *>* argsList = new (comp()->trStackMemory()) TR::list<TR::SymbolReference*>(getTypedAllocator<TR::SymbolReference*>(comp()->allocator()));566for (int i = 0; i < node->getNumChildren(); i++)567{568TR::Node * currentChild = node->getChild(i);569TR::SymbolReference *newSymbolReference = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(), currentChild->getDataType());570argsList->push_back(newSymbolReference);571TR::Node * storeNode = TR::Node::createStore(node, newSymbolReference, currentChild);572treetop->insertBefore(TR::TreeTop::create(comp(),storeNode));573inlCallNode->setAndIncChild(i, TR::Node::createLoad(node, newSymbolReference));574currentChild->recursivelyDecReferenceCount();575}576577TR::Node* mhNode = TR::Node::createLoad(node, argsList->front()); // the first arg of invokeBasic call is the receiver MethodHandle object578// load MethodHandle.form, which is the LambdaForm object579uint32_t offset = fej9->getInstanceFieldOffsetIncludingHeader("Ljava/lang/invoke/MethodHandle;", "form", "Ljava/lang/invoke/LambdaForm;", comp()->getCurrentMethod());580TR::SymbolReference * lambdaFormSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(comp()->getMethodSymbol(),581TR::Symbol::Java_lang_invoke_MethodHandle_form,582TR::Address,583offset,584false,585false,586true,587"java/lang/invoke/MethodHandle.form Ljava/lang/invoke/LambdaForm;");588TR::Node * lambdaFormNode = TR::Node::createWithSymRef(node, comp()->il.opCodeForIndirectLoad(TR::Address), 1 , mhNode, lambdaFormSymRef);589lambdaFormNode->setIsNonNull(true);590// load from lambdaForm.vmEntry, which is the MemberName object591offset = fej9->getInstanceFieldOffsetIncludingHeader("Ljava/lang/invoke/LambdaForm;", "vmentry", "Ljava/lang/invoke/MemberName;", comp()->getCurrentMethod());592TR::SymbolReference * memberNameSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(comp()->getMethodSymbol(),593TR::Symbol::Java_lang_invoke_LambdaForm_vmentry,594TR::Address,595offset,596false,597false,598true,599"java/lang/invoke/LambdaForm.vmentry Ljava/lang/invoke/MemberName;");600TR::Node * memberNameNode = TR::Node::createWithSymRef(node, comp()->il.opCodeForIndirectLoad(TR::Address), 1, lambdaFormNode, memberNameSymRef);601// load from membername.vmTarget, which is the J9Method602TR::SymbolReference * vmTargetSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(comp()->getMethodSymbol(),603TR::Symbol::Java_lang_invoke_MemberName_vmtarget,604TR::Address,605fej9->getVMTargetOffset(),606false,607false,608true,609"java/lang/invoke/MemberName.vmtarget J");610vmTargetSymRef->getSymbol()->setNotCollected();611TR::Node * vmTargetNode = TR::Node::createWithSymRef(node, TR::aloadi, 1, memberNameNode, vmTargetSymRef);612processVMInternalNativeFunction(treetop, node, vmTargetNode, argsList, inlCallNode);613}614615void J9::RecognizedCallTransformer::process_java_lang_invoke_MethodHandle_linkToStaticSpecial(TR::TreeTop* treetop, TR::Node* node)616{617TR_J9VMBase* fej9 = static_cast<TR_J9VMBase*>(comp()->fe());618TR::TransformUtil::separateNullCheck(comp(), treetop, true);619TR::Node * inlCallNode = node->duplicateTree(false);620TR::list<TR::SymbolReference *>* argsList = new (comp()->trStackMemory()) TR::list<TR::SymbolReference*>(getTypedAllocator<TR::SymbolReference*>(comp()->allocator()));621for (int i = 0; i < node->getNumChildren(); i++)622{623TR::Node * currentChild = node->getChild(i);624TR::SymbolReference *newSymbolReference = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(), currentChild->getDataType());625argsList->push_back(newSymbolReference);626TR::Node * storeNode = TR::Node::createStore(node, newSymbolReference, currentChild);627treetop->insertBefore(TR::TreeTop::create(comp(),storeNode));628inlCallNode->setAndIncChild(i, TR::Node::createLoad(node, newSymbolReference));629currentChild->recursivelyDecReferenceCount();630}631// load from membername.vmTarget, which is the J9Method632TR::Node* mnNode = TR::Node::createLoad(node, argsList->back());633TR::SymbolReference * vmTargetSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(comp()->getMethodSymbol(),634TR::Symbol::Java_lang_invoke_MemberName_vmtarget,635TR::Address,636fej9->getVMTargetOffset(),637false,638false,639true,640"java/lang/invoke/MemberName.vmtarget J");641vmTargetSymRef->getSymbol()->setNotCollected();642TR::Node * vmTargetNode = TR::Node::createWithSymRef(node, TR::aloadi, 1, mnNode, vmTargetSymRef);643vmTargetNode->setIsNonNull(true);644argsList->pop_back(); // MemberName is not required when dispatching directly to the jitted method address645processVMInternalNativeFunction(treetop, node, vmTargetNode, argsList, inlCallNode);646}647648void J9::RecognizedCallTransformer::processVMInternalNativeFunction(TR::TreeTop* treetop, TR::Node* node, TR::Node* vmTargetNode, TR::list<TR::SymbolReference *>* argsList, TR::Node* inlCallNode)649{650TR::SymbolReference *extraField = comp()->getSymRefTab()->findOrCreateJ9MethodExtraFieldSymbolRef(offsetof(struct J9Method, extra));651TR::Node *extra = TR::Node::createWithSymRef(node, comp()->il.opCodeForIndirectLoad(extraField->getSymbol()->getDataType()), 1, vmTargetNode, extraField);652TR::SymbolReference *extraTempSlotSymRef = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(),extraField->getSymbol()->getDataType());653treetop->insertBefore(TR::TreeTop::create(comp(), TR::Node::createStore(node, extraTempSlotSymRef, extra)));654655TR::ILOpCodes xcmpne = comp()->target().is64Bit()? TR::iflcmpne : TR::ificmpne;656TR::ILOpCodes xand = comp()->target().is64Bit()? TR::land : TR::iand;657TR::Node *zero = comp()->target().is64Bit()? TR::Node::lconst(node, 0) : TR::Node::iconst(node, 0);658TR::Node *mask = comp()->target().is64Bit()? TR::Node::lconst(node, J9_STARTPC_NOT_TRANSLATED) : TR::Node::iconst(node, J9_STARTPC_NOT_TRANSLATED);659660TR::Node* isCompiledNode = TR::Node::createif(xcmpne,661TR::Node::create(xand, 2, TR::Node::createLoad(node, extraTempSlotSymRef), mask),662zero,663NULL);664isCompiledNode->copyByteCodeInfo(node);665TR::TreeTop * cmpCheckTreeTop = TR::TreeTop::create(self()->comp(), isCompiledNode);666667TR::Node *jitAddress;668if (comp()->target().cpu.isI386())669{670jitAddress = TR::Node::create(TR::i2l, 1, TR::Node::createLoad(node, extraTempSlotSymRef));671}672else673{674TR::SymbolReference *linkageInfoSymRef = comp()->getSymRefTab()->findOrCreateStartPCLinkageInfoSymbolRef(-4);675TR::ILOpCodes x2a = comp()->target().is64Bit()? TR::l2a : TR::i2a;676TR::Node *linkageInfo = TR::Node::createWithSymRef(TR::iloadi, 1, 1, TR::Node::create(x2a, 1, TR::Node::createLoad(node, extraTempSlotSymRef)), linkageInfoSymRef);677TR::Node *jitEntryOffset = TR::Node::create(TR::ishr, 2, linkageInfo, TR::Node::iconst(node, 16));678if (comp()->target().is64Bit())679jitAddress = TR::Node::create(TR::ladd, 2, TR::Node::createLoad(node, extraTempSlotSymRef), TR::Node::create(TR::i2l, 1, jitEntryOffset));680else681jitAddress = TR::Node::create(TR::iadd, 2, TR::Node::createLoad(node, extraTempSlotSymRef), jitEntryOffset);682}683TR_J9VMBase* fej9 = static_cast<TR_J9VMBase*>(comp()->fe());684TR_OpaqueMethodBlock *dummyInvoke = fej9->getMethodFromName("com/ibm/jit/JITHelpers", "dispatchComputedStaticCall", "()V");685int signatureLength;686char * signature = getSignatureForComputedCall(687"J",688"",689comp(),690node->getSymbol()->castToMethodSymbol()->getMethod()->signatureChars(),691signatureLength);692693// construct a dummy resolved method694TR::ResolvedMethodSymbol * owningMethodSymbol = node->getSymbolReference()->getOwningMethodSymbol(comp());695TR_ResolvedMethod * dummyMethod = fej9->createResolvedMethodWithSignature(comp()->trMemory(),dummyInvoke, NULL, signature,signatureLength, owningMethodSymbol->getResolvedMethod());696TR::SymbolReference * computedCallSymbol = comp()->getSymRefTab()->findOrCreateMethodSymbol(owningMethodSymbol->getResolvedMethodIndex(), -1, dummyMethod, TR::MethodSymbol::ComputedStatic);697698uint32_t numComputedCallArgs = argsList->size() + 1;699TR::Node * computedCallNode = TR::Node::createWithSymRef(node, node->getSymbol()->castToMethodSymbol()->getMethod()->indirectCallOpCode(),numComputedCallArgs, computedCallSymbol);700computedCallNode->setAndIncChild(0,jitAddress); // first arguments of computed calls is the method address to jump to701int32_t child_i = 1;702for (auto symRefIt = argsList->begin(); symRefIt != argsList->end(); ++symRefIt)703{704TR::SymbolReference * currentArg = *symRefIt;705computedCallNode->setAndIncChild(child_i, TR::Node::createLoad(node, currentArg));706child_i++;707}708TR::TreeTop * computedCallTreeTop = TR::TreeTop::create(comp(), TR::Node::create(node, TR::treetop, 1, computedCallNode));709TR::RecognizedMethod rm = node->getSymbol()->castToMethodSymbol()->getMandatoryRecognizedMethod();710TR::Node *nullChkNode = NULL;711if (rm == TR::java_lang_invoke_MethodHandle_linkToSpecial || rm == TR::java_lang_invoke_MethodHandle_linkToVirtual)712{713TR::Node *passthroughNode = TR::Node::create(node, TR::PassThrough, 1);714passthroughNode->setAndIncChild(0, TR::Node::createLoad(node, argsList->front()));715TR::SymbolReference *symRef = comp()->getSymRefTab()->findOrCreateNullCheckSymbolRef(comp()->getMethodSymbol());716nullChkNode = TR::Node::createWithSymRef(TR::NULLCHK, 1, 1, passthroughNode, symRef);717}718719TR::TreeTop * inlCallTreeTop = TR::TreeTop::create(comp(), TR::Node::create(node, TR::treetop, 1, inlCallNode)); // original treetop gets deleted by createDiamondForCall720TR::TransformUtil::createDiamondForCall(this, treetop, cmpCheckTreeTop, inlCallTreeTop, computedCallTreeTop, false, false);721if (nullChkNode) computedCallTreeTop->insertBefore(TR::TreeTop::create(comp(), nullChkNode));722_processedINLCalls->set(inlCallNode->getGlobalIndex());723}724725void J9::RecognizedCallTransformer::process_java_lang_invoke_MethodHandle_linkToVirtual(TR::TreeTop * treetop, TR::Node * node)726{727TR_J9VMBase* fej9 = static_cast<TR_J9VMBase*>(comp()->fe());728TR::Node * placeholderINLCallNode = node->duplicateTree(false); // this will be eventually removed once the second diamond is created729TR::Node* duplicatedINLCallNode = node->duplicateTree(false);730TR::list<TR::SymbolReference *>* argsList = new (comp()->trStackMemory()) TR::list<TR::SymbolReference*>(getTypedAllocator<TR::SymbolReference*>(comp()->allocator()));731for (int i = 0; i < node->getNumChildren(); i++)732{733TR::Node * currentChild = node->getChild(i);734TR::SymbolReference *newSymbolReference = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(), currentChild->getDataType());735newSymbolReference->getSymbol()->setNotCollected();736argsList->push_back(newSymbolReference);737TR::Node * storeNode = TR::Node::createStore(node, newSymbolReference, currentChild);738treetop->insertBefore(TR::TreeTop::create(comp(),storeNode));739placeholderINLCallNode->setAndIncChild(i, TR::Node::createLoad(node, newSymbolReference));740duplicatedINLCallNode->setAndIncChild(i, TR::Node::createLoad(node, newSymbolReference));741currentChild->recursivelyDecReferenceCount();742currentChild->recursivelyDecReferenceCount(); // ref count has to be decremented twice as there were two duplicates of the parent made743}744745TR::SymbolReference *receiverSymRef = argsList->front();746TR::SymbolReference *mnSymRef = argsList->back();747748// -------- construct trees to obtain and check if vTableIndex > 0 --------749// get JIT Vtable index from membername.vmindex750TR::SymbolReference* vmindexSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(comp()->getMethodSymbol(),751TR::Symbol::Java_lang_invoke_MemberName_vmindex,752TR::Address,753fej9->getVMIndexOffset(),754false,755false,756true,757"java/lang/invoke/MemberName.vmindex J");758vmindexSymRef->getSymbol()->setNotCollected();759760// construct trees to check if vtable index is zero (NOT MemberName.vmindex, but MN.vmindex.vtableindex). if zero, then call will be dispatched similar to linkToStatic.761TR::Node * j9JNIMethodIdNode = TR::Node::createWithSymRef(node, TR::aloadi, 1, TR::Node::createLoad(node, mnSymRef), vmindexSymRef);762TR::SymbolReference* vtableIndexSymRef = comp()->getSymRefTab()->findOrCreateJ9JNIMethodIDvTableIndexFieldSymbol(offsetof(struct J9JNIMethodID, vTableIndex));763vtableIndexSymRef->getSymbol()->setNotCollected();764TR::Node* vtableIndexNode = TR::Node::createWithSymRef(node, comp()->il.opCodeForIndirectLoad(vtableIndexSymRef->getSymbol()->getDataType()), 1, j9JNIMethodIdNode , vtableIndexSymRef);765TR::SymbolReference* vtableOffsetTempSlotSymRef = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(),vtableIndexNode->getSymbol()->getDataType());766vtableOffsetTempSlotSymRef->getSymbol()->setNotCollected();767treetop->insertBefore(TR::TreeTop::create(comp(), TR::Node::createStore(node, vtableOffsetTempSlotSymRef, vtableIndexNode)));768TR::ILOpCodes ifxcmpne = comp()->target().is64Bit()? TR::iflcmpne : TR::ificmpne;769TR::Node *zero = comp()->target().is64Bit()? TR::Node::lconst(node, 0) : TR::Node::iconst(node, 0);770771TR::Node* vTableOffsetIsNotZero = TR::Node::createif(ifxcmpne,772TR::Node::createLoad(node, vtableOffsetTempSlotSymRef),773zero,774NULL);775TR::TreeTop* vtableOffsetIsNotZeroTreeTop = TR::TreeTop::create(comp(), vTableOffsetIsNotZero);776777// -------- construct trees for path to take when vtable index > 0 --------778779// construct a dummy "resolved method" for dispatch virtual:780TR_OpaqueMethodBlock *dummyInvoke = fej9->getMethodFromName("com/ibm/jit/JITHelpers", "dispatchVirtual", "()V");781int signatureLength;782char * signature = getSignatureForComputedCall(783"JJ",784"",785comp(),786node->getSymbol()->castToMethodSymbol()->getMethod()->signatureChars(),787signatureLength);788TR::ResolvedMethodSymbol * owningMethodSymbol = node->getSymbolReference()->getOwningMethodSymbol(comp());789TR_ResolvedMethod * dummyMethod = fej9->createResolvedMethodWithSignature(comp()->trMemory(),dummyInvoke, NULL, signature, signatureLength, owningMethodSymbol->getResolvedMethod());790TR::SymbolReference * methodSymRef = comp()->getSymRefTab()->findOrCreateMethodSymbol(owningMethodSymbol->getResolvedMethodIndex(), -1, dummyMethod, TR::MethodSymbol::ComputedStatic);791792// construct trees to load target method address (which will either be a thunk or compiled method address) from VFT, but for simplicity let's call it a jitted method entry point793TR::Node * xconstSizeofJ9Class = comp()->target().is64Bit()794? TR::Node::lconst(node, sizeof(J9Class))795: TR::Node::iconst(node, sizeof(J9Class));796797TR::ILOpCodes subOp = comp()->target().is64Bit() ? TR::lsub : TR::isub;798TR::ILOpCodes axadd = comp()->target().is64Bit() ? TR::aladd : TR::aiadd;799TR::Node* jitVFTOffset = TR::Node::create(subOp, 2, xconstSizeofJ9Class, TR::Node::createLoad(node, vtableOffsetTempSlotSymRef));800TR::SymbolReference * vftSymRef = comp()->getSymRefTab()->findOrCreateVftSymbolRef();801TR::Node * vftNode = TR::Node::createWithSymRef(node, TR::aloadi, 1, TR::Node::createLoad(node, receiverSymRef), vftSymRef);802TR::Node * jitVFTSlotPtr = TR::Node::create(axadd, 2, vftNode, jitVFTOffset);803TR::SymbolReference *tSymRef = comp()->getSymRefTab()->findOrCreateGenericIntShadowSymbolReference(0);804tSymRef->getSymbol()->setNotCollected();805TR::ILOpCodes loadOp = comp()->target().is64Bit() ? TR::lloadi : TR::iloadi;806// arg0 ---> jitted method address (in JIT vtable)807TR::Node * jittedMethodEntryPoint = TR::Node::createWithSymRef(loadOp, 1, 1, jitVFTSlotPtr, tSymRef);808809// arg1 ---> vtable slot index (jitVFTOffset)810811// 2 additional args prepended (address in vtable entry and vtable slot index), and last arg (MemberName object) removed, so net 1 extra child812uint32_t numChildren = node->getNumChildren() + 1;813TR::Node * dispatchVirtualCallNode = TR::Node::createWithSymRef(node, node->getSymbol()->castToMethodSymbol()->getMethod()->indirectCallOpCode(), numChildren, methodSymRef);814815// set children for the dispatchVirtual call node816dispatchVirtualCallNode->setAndIncChild(0, jittedMethodEntryPoint);817dispatchVirtualCallNode->setAndIncChild(1, jitVFTOffset);818argsList->pop_back(); //remove MemberName object819int32_t child_i = 2;820for (auto symRefIt = argsList->begin(); symRefIt != argsList->end(); ++symRefIt)821{822TR::SymbolReference * currentArg = *symRefIt;823dispatchVirtualCallNode->setAndIncChild(child_i, TR::Node::createLoad(node, currentArg));824child_i++;825}826827TR::TreeTop * dispatchVirtualTreeTop = TR::TreeTop::create(comp(), TR::Node::create(node, TR::treetop, 1, dispatchVirtualCallNode));828TR::TreeTop * placeholderINLCallTreeTop = TR::TreeTop::create(comp(), TR::Node::create(node, TR::treetop, 1, placeholderINLCallNode));829830TR::Node *passthroughNode = TR::Node::create(node, TR::PassThrough, 1);831passthroughNode->setAndIncChild(0, TR::Node::createLoad(node, argsList->front()));832TR::SymbolReference *nullSymRef = comp()->getSymRefTab()->findOrCreateNullCheckSymbolRef(comp()->getMethodSymbol());833TR::Node* nullChkNode = TR::Node::createWithSymRef(TR::NULLCHK, 1, 1, passthroughNode, nullSymRef);834835node->removeAllChildren();836TR::TransformUtil::createDiamondForCall(this, treetop, vtableOffsetIsNotZeroTreeTop, dispatchVirtualTreeTop, placeholderINLCallTreeTop, false, false);837TR::TreeTop *virtualNullCheckTreeTop = TR::TreeTop::create(comp(), nullChkNode);838dispatchVirtualTreeTop->insertBefore(virtualNullCheckTreeTop);839840// Insert a conditional at the beginning of the virtual call path to841// determine the VFT offset for interface methods.842TR::Block *virtualNullCheckBlock = virtualNullCheckTreeTop->getEnclosingBlock();843TR::CFG *cfg = comp()->getFlowGraph();844TR::Block *itableLookupBlock = virtualNullCheckBlock->split(dispatchVirtualTreeTop, cfg, true);845TR::Block *virtualDispatchBlock = itableLookupBlock->split(dispatchVirtualTreeTop, cfg, true);846847TR::ILOpCodes andOp = comp()->target().is64Bit() ? TR::land : TR::iand;848TR::Node * xconstITableFlagBit = comp()->target().is64Bit()849? TR::Node::lconst(node, J9_JNI_MID_INTERFACE)850: TR::Node::iconst(node, (int32_t)J9_JNI_MID_INTERFACE);851852TR::ILOpCodes ifxcmpeq = TR::ILOpCode(ifxcmpne).getOpCodeForReverseBranch();853// The offset is a VFT offset iff it is not an itable index854TR::Node * ifIsVFTOffset = TR::Node::createif(855ifxcmpeq,856TR::Node::create(857node,858andOp,8592,860TR::Node::createLoad(node, vtableOffsetTempSlotSymRef),861xconstITableFlagBit),862zero->duplicateTree(), // safe because zero is a constant863virtualDispatchBlock->getEntry());864865virtualNullCheckBlock->append(TR::TreeTop::create(comp(), ifIsVFTOffset));866cfg->addEdge(virtualNullCheckBlock, virtualDispatchBlock);867868// TODO: For linkToInterface() we should instead use869// findOrCreateLookupDynamicPublicInterfaceMethodSymbolRef(), which will870// throw IllegalAccessError when the dispatched method is non-public.871TR::Node *vftOffsetFromITable = TR::Node::createWithSymRef(872node,873comp()->target().is64Bit() ? TR::lcall : TR::icall,8743,875comp()->getSymRefTab()->findOrCreateLookupDynamicInterfaceMethodSymbolRef());876877// The first argument to the itable lookup helper is the receiver class.878// It's safe to duplicate vftNode here because it is just a load of879// <vft-symbol> from a load of a temp, and the temp has been created880// specifically to hold the receiver reference - there are no other defs.881//882// NOTE: This child is actually last because helper arguments are passed in883// reverse order.884//885vftOffsetFromITable->setAndIncChild(2, vftNode->duplicateTree());886887// The next argument to the itable lookup helper is the interface class.888const bool vmtargetIsVolatile = false;889const bool vmtargetIsPrivate = false; // could be true? It's a hidden field890const bool vmtargetIsFinal = true;891TR::SymbolReference * vmtargetSymRef =892comp()->getSymRefTab()->findOrFabricateShadowSymbol(893comp()->getMethodSymbol(),894TR::Symbol::Java_lang_invoke_MemberName_vmtarget,895TR::Address,896fej9->getVMTargetOffset(),897vmtargetIsVolatile,898vmtargetIsPrivate,899vmtargetIsFinal,900"java/lang/invoke/MemberName.vmtarget J");901902vmtargetSymRef->getSymbol()->setNotCollected();903904TR::Node * vmTargetNode = TR::Node::createWithSymRef(905node, TR::aloadi, 1, TR::Node::createLoad(node, mnSymRef), vmtargetSymRef);906907TR::SymbolReference *cpField =908comp()->getSymRefTab()->findOrCreateJ9MethodConstantPoolFieldSymbolRef(909offsetof(struct J9Method, constantPool));910911TR::Node *cpAddrIntWithFlags = TR::Node::createWithSymRef(912node, loadOp, 1, vmTargetNode, cpField);913914TR::Node *cpAddrMask = comp()->target().is64Bit()915? TR::Node::lconst(~(int64_t)J9_STARTPC_STATUS)916: TR::Node::iconst(~(int32_t)J9_STARTPC_STATUS);917918TR::Node *cpAddrInt = TR::Node::create(919node, andOp, 2, cpAddrIntWithFlags, cpAddrMask);920921TR::ILOpCodes x2a = comp()->target().is64Bit() ? TR::l2a : TR::i2a;922TR::Node *cpAddr = TR::Node::create(node, x2a, 1, cpAddrInt);923924TR::Node *ramClassFieldOffset = comp()->target().is64Bit()925? TR::Node::lconst(offsetof (struct J9ConstantPool, ramClass))926: TR::Node::iconst(offsetof (struct J9ConstantPool, ramClass));927928TR::Node *ramClassFieldAddr = TR::Node::create(929node, axadd, 2, cpAddr, ramClassFieldOffset);930931TR::Node *interfaceClassInt = TR::Node::createWithSymRef(932node, loadOp, 1, ramClassFieldAddr, tSymRef);933934TR::Node *interfaceClass = TR::Node::create(node, x2a, 1, interfaceClassInt);935vftOffsetFromITable->setAndIncChild(1, interfaceClass);936937// The final argument to the itable lookup helper is the itable index.938// NOTE: This child is actually first because helper arguments are passed in939// reverse order.940TR::Node *xconstClearITableFlagMask = comp()->target().is64Bit()941? TR::Node::lconst(node, ~(int64_t)J9_JNI_MID_INTERFACE)942: TR::Node::iconst(node, ~(int32_t)J9_JNI_MID_INTERFACE);943944// Duplicate xconstITableFlagBit to prevent commoning between blocks. The945// duplication is safe because it's a constant.946xconstITableFlagBit = xconstITableFlagBit->duplicateTree();947TR::Node *itableIndex = TR::Node::create(948andOp,9492,950TR::Node::createLoad(node, vtableOffsetTempSlotSymRef),951xconstClearITableFlagMask);952953vftOffsetFromITable->setAndIncChild(0, itableIndex);954955itableLookupBlock->append(956TR::TreeTop::create(957comp(),958TR::Node::create(node, TR::treetop, 1, vftOffsetFromITable)));959960itableLookupBlock->append(961TR::TreeTop::create(962comp(),963TR::Node::createStore(964node, vtableOffsetTempSlotSymRef, vftOffsetFromITable)));965966// -------- path if vmIndex == 0 --------967// now let's work with just the placeholder INL call as the main node, as if this is a linkToStatic/Special call. the original treetop was removed.968treetop = placeholderINLCallTreeTop;969node = treetop->getNode()->getFirstChild();970971// It's safe to duplicate vmTargetNode because it's just a load of vmtarget972// from a load of a temp, and the temp has been created specifically to hold973// the MemberName reference - there are no other defs974vmTargetNode = vmTargetNode->duplicateTree();975976processVMInternalNativeFunction(treetop, node, vmTargetNode, argsList, duplicatedINLCallNode);977}978#endif // J9VM_OPT_OPENJDK_METHODHANDLE979980bool J9::RecognizedCallTransformer::isInlineable(TR::TreeTop* treetop)981{982auto node = treetop->getNode()->getFirstChild();983TR::RecognizedMethod rm =984node->getSymbol()->castToMethodSymbol()->getMandatoryRecognizedMethod();985986bool isILGenPass = !getLastRun();987if (isILGenPass)988{989switch(rm)990{991case TR::sun_misc_Unsafe_getAndAddInt:992return !comp()->getOption(TR_DisableUnsafe) && !comp()->compileRelocatableCode() && !TR::Compiler->om.canGenerateArraylets() &&993cg()->supportsNonHelper(TR::SymbolReferenceTable::atomicFetchAndAddSymbol);994case TR::sun_misc_Unsafe_getAndSetInt:995return !comp()->getOption(TR_DisableUnsafe) && !comp()->compileRelocatableCode() && !TR::Compiler->om.canGenerateArraylets() &&996cg()->supportsNonHelper(TR::SymbolReferenceTable::atomicSwapSymbol);997case TR::sun_misc_Unsafe_getAndAddLong:998return !comp()->getOption(TR_DisableUnsafe) && !comp()->compileRelocatableCode() && !TR::Compiler->om.canGenerateArraylets() && comp()->target().is64Bit() &&999cg()->supportsNonHelper(TR::SymbolReferenceTable::atomicFetchAndAddSymbol);1000case TR::sun_misc_Unsafe_getAndSetLong:1001return !comp()->getOption(TR_DisableUnsafe) && !comp()->compileRelocatableCode() && !TR::Compiler->om.canGenerateArraylets() && comp()->target().is64Bit() &&1002cg()->supportsNonHelper(TR::SymbolReferenceTable::atomicSwapSymbol);1003case TR::java_lang_Class_isAssignableFrom:1004return cg()->supportsInliningOfIsAssignableFrom();1005case TR::java_lang_Integer_rotateLeft:1006case TR::java_lang_Integer_rotateRight:1007return comp()->target().cpu.getSupportsHardware32bitRotate();1008case TR::java_lang_Long_rotateLeft:1009case TR::java_lang_Long_rotateRight:1010return comp()->target().cpu.getSupportsHardware64bitRotate();1011case TR::java_lang_Math_abs_I:1012case TR::java_lang_Math_abs_L:1013return cg()->supportsIntAbs();1014case TR::java_lang_Math_abs_F:1015case TR::java_lang_Math_abs_D:1016return cg()->supportsFPAbs();1017case TR::java_lang_Math_max_I:1018case TR::java_lang_Math_min_I:1019case TR::java_lang_Math_max_L:1020case TR::java_lang_Math_min_L:1021return !comp()->getOption(TR_DisableMaxMinOptimization);1022case TR::java_lang_StringUTF16_toBytes:1023return !comp()->compileRelocatableCode();1024case TR::java_lang_StrictMath_sqrt:1025case TR::java_lang_Math_sqrt:1026return comp()->target().cpu.getSupportsHardwareSQRT();1027case TR::java_lang_Short_reverseBytes:1028case TR::java_lang_Integer_reverseBytes:1029case TR::java_lang_Long_reverseBytes:1030return comp()->cg()->supportsByteswap();1031case TR::java_lang_StringCoding_encodeASCII:1032case TR::java_lang_String_encodeASCII:1033return comp()->cg()->getSupportsInlineEncodeASCII();1034default:1035return false;1036}1037}1038#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)1039else1040{1041// Post-inlining pass1042switch (rm)1043{1044case TR::java_lang_invoke_MethodHandle_invokeBasic:1045if (_processedINLCalls->get(node->getGlobalIndex()))1046return false;1047else1048return true;1049case TR::java_lang_invoke_MethodHandle_linkToStatic:1050case TR::java_lang_invoke_MethodHandle_linkToSpecial:1051// linkToStatic calls are also used for unresolved invokedynamic/invokehandle, which we can not1052// bypass as we may push null appendix object that we can not check at compile time1053if (_processedINLCalls->get(node->getGlobalIndex()) || node->getSymbolReference()->getSymbol()->isDummyResolvedMethod())1054return false;1055else1056return true;1057case TR::java_lang_invoke_MethodHandle_linkToVirtual:1058if (_processedINLCalls->get(node->getGlobalIndex()))1059return false;1060else1061return true;1062default:1063return false;1064}1065}1066#else1067return false;1068#endif1069}10701071void J9::RecognizedCallTransformer::transform(TR::TreeTop* treetop)1072{1073auto node = treetop->getNode()->getFirstChild();1074TR::RecognizedMethod rm =1075node->getSymbol()->castToMethodSymbol()->getMandatoryRecognizedMethod();10761077bool isILGenPass = !getLastRun();1078if (isILGenPass)1079{1080switch(rm)1081{1082case TR::sun_misc_Unsafe_getAndAddInt:1083case TR::sun_misc_Unsafe_getAndAddLong:1084processUnsafeAtomicCall(treetop, TR::SymbolReferenceTable::atomicFetchAndAddSymbol);1085break;1086case TR::sun_misc_Unsafe_getAndSetInt:1087case TR::sun_misc_Unsafe_getAndSetLong:1088processUnsafeAtomicCall(treetop, TR::SymbolReferenceTable::atomicSwapSymbol);1089break;1090case TR::java_lang_Class_isAssignableFrom:1091process_java_lang_Class_IsAssignableFrom(treetop, node);1092break;1093case TR::java_lang_Integer_rotateLeft:1094processIntrinsicFunction(treetop, node, TR::irol);1095break;1096case TR::java_lang_Integer_rotateRight:1097{1098// rotateRight(x, distance) = rotateLeft(x, -distance)1099TR::Node *distance = TR::Node::create(node, TR::ineg, 1);1100distance->setChild(0, node->getSecondChild());1101node->setAndIncChild(1, distance);11021103processIntrinsicFunction(treetop, node, TR::irol);11041105break;1106}1107case TR::java_lang_Long_rotateLeft:1108processIntrinsicFunction(treetop, node, TR::lrol);1109break;1110case TR::java_lang_Long_rotateRight:1111{1112// rotateRight(x, distance) = rotateLeft(x, -distance)1113TR::Node *distance = TR::Node::create(node, TR::ineg, 1);1114distance->setChild(0, node->getSecondChild());1115node->setAndIncChild(1, distance);11161117processIntrinsicFunction(treetop, node, TR::lrol);11181119break;1120}1121case TR::java_lang_Math_abs_I:1122processIntrinsicFunction(treetop, node, TR::iabs);1123break;1124case TR::java_lang_Math_abs_L:1125processIntrinsicFunction(treetop, node, TR::labs);1126break;1127case TR::java_lang_Math_abs_D:1128processIntrinsicFunction(treetop, node, TR::dabs);1129break;1130case TR::java_lang_Math_abs_F:1131processIntrinsicFunction(treetop, node, TR::fabs);1132break;1133case TR::java_lang_Math_max_I:1134processIntrinsicFunction(treetop, node, TR::imax);1135break;1136case TR::java_lang_Math_min_I:1137processIntrinsicFunction(treetop, node, TR::imin);1138break;1139case TR::java_lang_Math_max_L:1140processIntrinsicFunction(treetop, node, TR::lmax);1141break;1142case TR::java_lang_Math_min_L:1143processIntrinsicFunction(treetop, node, TR::lmin);1144break;1145case TR::java_lang_StringUTF16_toBytes:1146process_java_lang_StringUTF16_toBytes(treetop, node);1147break;1148case TR::java_lang_StringCoding_encodeASCII:1149case TR::java_lang_String_encodeASCII:1150process_java_lang_StringCoding_encodeASCII(treetop, node);1151break;1152case TR::java_lang_StrictMath_sqrt:1153case TR::java_lang_Math_sqrt:1154process_java_lang_StrictMath_and_Math_sqrt(treetop, node);1155break;1156case TR::java_lang_Short_reverseBytes:1157processConvertingUnaryIntrinsicFunction(treetop, node, TR::i2s, TR::sbyteswap, TR::s2i);1158break;1159case TR::java_lang_Integer_reverseBytes:1160processIntrinsicFunction(treetop, node, TR::ibyteswap);1161break;1162case TR::java_lang_Long_reverseBytes:1163processIntrinsicFunction(treetop, node, TR::lbyteswap);1164break;1165default:1166break;1167}1168}1169#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)1170else1171{1172// Post-inlining pass1173switch (rm)1174{1175case TR::java_lang_invoke_MethodHandle_invokeBasic:1176process_java_lang_invoke_MethodHandle_invokeBasic(treetop, node);1177break;1178case TR::java_lang_invoke_MethodHandle_linkToStatic:1179case TR::java_lang_invoke_MethodHandle_linkToSpecial:1180process_java_lang_invoke_MethodHandle_linkToStaticSpecial(treetop, node);1181break;1182case TR::java_lang_invoke_MethodHandle_linkToVirtual:1183process_java_lang_invoke_MethodHandle_linkToVirtual(treetop, node);1184break;1185default:1186break;1187}1188}1189#endif1190}119111921193