Path: blob/master/runtime/compiler/optimizer/DynamicLiteralPool.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2000, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "optimizer/DynamicLiteralPool.hpp"2324#include <limits.h>25#include <math.h>26#include <stddef.h>27#include <stdint.h>28#include <stdio.h>29#include <stdlib.h>30#include <string.h>31#include "codegen/CodeGenerator.hpp"32#include "env/FrontEnd.hpp"33#include "compile/Compilation.hpp"34#include "compile/Method.hpp"35#include "compile/SymbolReferenceTable.hpp"36#include "compile/VirtualGuard.hpp"37#include "control/Options.hpp"38#include "control/Options_inlines.hpp"39#include "env/CompilerEnv.hpp"40#include "env/PersistentInfo.hpp"41#include "env/StackMemoryRegion.hpp"42#include "env/TRMemory.hpp"43#include "env/jittypes.h"44#include "il/AliasSetInterface.hpp"45#include "il/Block.hpp"46#include "il/DataTypes.hpp"47#include "il/ILOpCodes.hpp"48#include "il/ILOps.hpp"49#include "il/Node.hpp"50#include "il/NodePool.hpp"51#include "il/Node_inlines.hpp"52#include "il/MethodSymbol.hpp"53#include "il/StaticSymbol.hpp"54#include "il/Symbol.hpp"55#include "il/SymbolReference.hpp"56#include "il/TreeTop.hpp"57#include "il/TreeTop_inlines.hpp"58#include "infra/Assert.hpp"59#include "infra/Cfg.hpp"60#include "infra/ILWalk.hpp"61#include "infra/Stack.hpp"62#include "infra/TRCfgEdge.hpp"63#include "infra/TRCfgNode.hpp"64#include "optimizer/Optimization.hpp"65#include "optimizer/Optimization_inlines.hpp"66#include "optimizer/OptimizationManager.hpp"67#include "optimizer/Optimizations.hpp"68#include "optimizer/Optimizer.hpp"69#include "optimizer/Structure.hpp"70#include "ras/Debug.hpp"71#include "runtime/J9Runtime.hpp"727374TR_DynamicLiteralPool::TR_DynamicLiteralPool(TR::OptimizationManager *manager)75: TR::Optimization(manager)76{77_litPoolAddressSym=NULL;78setAloadFromCurrentBlock(NULL);79_changed = false;80}8182int32_t TR_DynamicLiteralPool::perform()83{84if (!cg()->supportsOnDemandLiteralPool())85return 1;8687{88TR::StackMemoryRegion stackMemoryRegion(*trMemory());8990process(comp()->getStartTree(), NULL);9192if (performTransformation(comp(), "%s free reserved literal pool register\n", optDetailString()))93{94if (cg()->supportsOnDemandLiteralPool())95{96cg()->setOnDemandLiteralPoolRun(true);97cg()->enableLiteralPoolRegisterForGRA();98}99}100101postPerformOnBlocks();102} // scope of the stack memory region103104if (_changed)105{106optimizer()->setUseDefInfo(NULL);107optimizer()->setValueNumberInfo(NULL);108optimizer()->setAliasSetsAreValid(false);109requestOpt(OMR::localCSE, true);110}111// need that to remove the astore if no literal pool is required112requestOpt(OMR::localDeadStoreElimination, true);113114return 1;115}116117118int32_t TR_DynamicLiteralPool::performOnBlock(TR::Block *block)119{120if (block->getEntry())121process(block->getEntry(), block->getEntry()->getExtendedBlockExitTreeTop()->getNextTreeTop());122return 0;123}124125126void TR_DynamicLiteralPool::initLiteralPoolBase()127{128TR::Node *tempValue;129TR::TreeTop *storeToTempTT;130TR::Node *firstNode,*storeToTemp;131TR::Block *firstBlock;132TR::SymbolReference * tempStaticSym;133134firstNode = comp()->getStartTree()->getNode();135firstBlock = firstNode->getBlock();136tempStaticSym = getSymRefTab()->createKnownStaticDataSymbolRef(0, TR::Address);137_litPoolAddressSym = getSymRefTab()->createTemporary(comp()->getMethodSymbol(), TR::Address);138139tempValue = TR::Node::createWithSymRef(firstNode, TR::aload, 0, tempStaticSym);140storeToTemp = TR::Node::createWithSymRef(TR::astore, 1, 1, tempValue, _litPoolAddressSym);141142tempStaticSym->setLiteralPoolAddress();143_litPoolAddressSym->setFromLiteralPool();144145// make sure GC knows about the two symbols, otherwise146// GC will examine the memory pointed to by the temp/static147// and will crash because the memory (i.e. the literal pool) is not a J9Object148tempStaticSym->getSymbol()->setNotCollected();149getLitPoolAddressSym()->getSymbol()->setNotCollected();150151storeToTempTT = TR::TreeTop::create(comp(), storeToTemp);152firstBlock->prepend(storeToTempTT);153_changed = true;154dumpOptDetails(comp(), "Literal pool base pointer initialized to %p \n", storeToTemp);155156}157158int32_t TR_DynamicLiteralPool::process(TR::TreeTop *startTree, TR::TreeTop *endTree)159{160TR::TreeTop *tt, *exitTree;161vcount_t visitCount = comp()->incVisitCount();162for (tt = startTree; (tt != endTree); tt = exitTree->getNextRealTreeTop())163{164TR::Block *block = tt->getNode()->getBlock();165_currentBlock=block;166exitTree = block->getEntry()->getExtendedBlockExitTreeTop();167processBlock(block, visitCount);168}169return 1;170}171172bool TR_DynamicLiteralPool::processBlock(TR::Block *block, vcount_t visitCount)173{174TR::TreeTop *exit = block->getEntry()->getExtendedBlockExitTreeTop();175setAloadFromCurrentBlock(NULL);176177for (TR::TreeTop *tt = block->getEntry(); tt != exit; tt = tt->getNextRealTreeTop())178{179setNumChild(-1);180visitTreeTop(tt, 0, 0, tt->getNode(), visitCount);181}182return true;183}184185bool TR_DynamicLiteralPool::visitTreeTop(TR::TreeTop * tt, TR::Node *grandParent, TR::Node *parent, TR::Node *node, vcount_t visitCount)186{187int32_t firstChild = 0;188189if (node->getVisitCount() == visitCount)190return true;191node->setVisitCount(visitCount);192193TR::ILOpCode opCode = node->getOpCode();194TR::ILOpCodes opCodeValue = opCode.getOpCodeValue();195196TR_OpaqueClassBlock * classInfo = 0;197198if (cg()->supportsOnDemandLiteralPool())199{200// do work on this node201if (opCode.isLoadConst())202{203// reset visitcount to make sure all parents see this child204if (node->getReferenceCount()>1) node->setVisitCount(visitCount-1);205206dumpOptDetails(comp(), "looking at const node %p (%s)\n", node, opCode.getName());207transformLitPoolConst(grandParent, parent,node);208}209else if (opCode.hasSymbolReference() &&210node->getSymbol()->isStatic() &&211!node->getSymbolReference()->isLiteralPoolAddress() &&212(node->getSymbolReference() != comp()->getSymRefTab()->findThisRangeExtensionSymRef()))213{214dumpOptDetails(comp(), "looking at the static symref for node %p (%s)\n", node, opCode.getName());215transformStaticSymRefToIndirectLoad(tt, parent, node);216}217218// add extra aload child for CurrentTimeMaxPrecision call219if (opCode.isCall() &&220comp()->getSymRefTab()->isNonHelper(node->getSymbolReference(), TR::SymbolReferenceTable::currentTimeMaxPrecisionSymbol))221{222addNewAloadChild(node);223}224// add extra aload child for float conversions225else if (opCodeValue==TR::fbits2i || opCodeValue==TR::dbits2l)226{227addNewAloadChild(node);228}229}230231for (int32_t i = firstChild; i < node->getNumChildren(); ++i)232{233setNumChild(i);234visitTreeTop(0, parent, node, node->getChild(i), visitCount);235}236return true;237}238239bool TR_DynamicLiteralPool::transformLitPoolConst(TR::Node *grandParent, TR::Node *parent, TR::Node *child)240{241switch (child->getOpCodeValue())242{243case TR::fconst:244if (performTransformation(comp(), "%s Float Constant\n", optDetailString()))245{246_changed = true;247transformConstToIndirectLoad(parent, child);248}249else250return false;251break;252case TR::dconst:253// LZDR can be used to load floating point zero254if (child->getDouble() != 0.0 && performTransformation(comp(), "%s Double Constant\n", optDetailString()))255{256_changed = true;257transformConstToIndirectLoad(parent, child);258}259else260return false;261break;262case TR::aconst:263if (child->isClassUnloadingConst())264return false;265case TR::iconst:266case TR::lconst:267case TR::bconst:268case TR::sconst:269if (transformNeeded(grandParent, parent, child))270{271if (performTransformation(comp(), "%s Large non-float Constant\n", optDetailString()))272{273_changed = true;274transformConstToIndirectLoad(parent, child);275}276else277{278return false;279}280}281break;282default:283if (child->getDataType().isBCD() || child->getDataType() == TR::Aggregate)284return false;285else286TR_ASSERT(false,"Unknown const %p (type %s)\n",child,child->getDataType().toString());287break;288}289return true;290}291292bool TR_DynamicLiteralPool::transformNeeded(TR::Node *grandParent, TR::Node *parent, TR::Node *child)293{294TR::ILOpCode parentOpCode = parent->getOpCode();295TR::ILOpCodes parentOpCodeValue = parentOpCode.getOpCodeValue();296297// need to ensure a constant setsign can be retrieved298if (parentOpCode.isSetSign())299return false;300301if (child->getType().isIntegral() && parentOpCode.skipDynamicLitPoolOnInts())302return false;303304// If the hardware supports relative fixed point loads/stores from the literal pool,305// i.e. On z10 or higher, LRL/LGRL/STRL/STGRL, then do not transform to use literal pool306// base register.307if ( (child->getType().isIntegral() || child->getType().isAddress()) &&308cg()->supportsDirectIntegralLoadStoresFromLiteralPool())309return false;310311// don't modify const children of multiplication or division to312// allow strength reduction to happen. The check bellow could be313// more precise, but the logic to determine if strength reduction314// is possible is quite complex and if we have it here, it needs315// be kept in sync with the logic in evaluators.316// In the worst case, when constant actually needs to go lit pool317// the code wiil insert extra LARL pre-loading lit pool entry318// The cost of this LARL is negligible considering the cost of MULT or DIV319if (parentOpCode.isMul() || parentOpCode.isDiv()) return false;320// If this looks like a pattern that could be evaluated to a test under mask type instruction321// then do not use the lit pool as this will obfuscate the pattern in the evaluator.322if (cg()->getSupportsTestUnderMask() &&323parentOpCode.isIf() &&324parent->getNumChildren() == 2 &&325parent->getSecondChild()->getOpCode().isLoadConst() &&326isPowerOf2(parent->getSecondChild()->get64bitIntegralValue()))327{328return false;329}330if (cg()->getSupportsTestUnderMask() &&331grandParent && grandParent->getOpCode().isIf() &&332parentOpCode.isAnd() &&333parent->getNumChildren() == 2 &&334parent->getSecondChild()->getOpCode().isLoadConst() &&335isPowerOf2(parent->getSecondChild()->get64bitIntegralValue()))336{337return false;338}339340// Check for arithmetic operations for add, sub, and non-guard compares.341// Guarded if-stmts might contain class pointers will may be unloaded. Such342// scenarios will be handled by constLoadNeedsLitPool below.343if (parentOpCode.isAdd() || parentOpCode.isSub() ||344(parentOpCode.isBooleanCompare() && !parent->isTheVirtualGuardForAGuardedInlinedCall()))345{346if (child->getOpCode().isLong() && (comp()->target().is32Bit()))347return false; //avasilev: to be handled better348else349{350TR::ILOpCodes oldOpCode = child->getOpCodeValue();351bool needs = (cg()->arithmeticNeedsLiteralFromPool(child));352TR::Node::recreate(child, oldOpCode);353return needs;354}355}356if (parentOpCode.isAnd() || parentOpCode.isOr() || parentOpCode.isXor() || parentOpCode.isNeg())357{358if (child->getOpCode().isLong() && (comp()->target().is32Bit()))359return false; // to be handled better360else361return (cg()->bitwiseOpNeedsLiteralFromPool(parent,child));362}363if (parentOpCode.isLeftShift() || parentOpCode.isRightShift() || parentOpCode.isShiftLogical())364return false;365366// TR::arraytranslateAndTest may throw AIOB, but that is taken care of by the evaluator. Also, the367// iconst may be the character to search.368if (parentOpCode.isBndCheck() && parentOpCodeValue != TR::arraytranslateAndTest)369return false;370371// TR::arrayset evaluator expects to see const child, and it's evaluated372// specially. Don't modify const children of TR::arrayset. See 74553373if (parentOpCodeValue == TR::arrayset) return false;374375if (child->isClassUnloadingConst()) return false;376377// TODO: This function can be simplified because the context in which it is used the following call will always result yield false.378// As such many paths through this function that return false are effectively dead and can be removed. There is only one path that379// does not return false, and this is the only path that needs to exist, though my intuition is that this path too should be verified380// as it may no longer be applicable.381return (cg()->constLoadNeedsLiteralFromPool(child));382}383384bool TR_DynamicLiteralPool::transformConstToIndirectLoad(TR::Node *parent, TR::Node *child)385{386//TR::Node *loadLiteralFromThePool;387//TR::Node *loadLiteralPoolAddress;388TR::Node *constCopy, *indirectLoad;389TR::SymbolReference *shadow;390391dumpOptDetails(comp(), "transforming const %p (%s)\n", child, child->getOpCode().getName());392393TR::Node *addrNode;394addrNode = getAloadFromCurrentBlock(parent);395396constCopy =TR::Node::copy(child);397shadow = getSymRefTab()->findOrCreateImmutableGenericIntShadowSymbolReference((intptr_t)constCopy);398shadow->setLiteralPoolAddress();399400if (child->getReferenceCount() > 1) // rematerialize the const by creating new indirect load node401{402indirectLoad=TR::Node::createWithSymRef(comp()->il.opCodeForIndirectLoad(child->getDataType()), 1, 1, addrNode, shadow);403dumpOptDetails(comp(), "New node created %p, refcount of const child was %d\n",indirectLoad,child->getReferenceCount());404parent->setAndIncChild(getNumChild(),indirectLoad);405child->decReferenceCount();406}407else408{409//convert const node to indirect load node410child->setNumChildren(1);411child = TR::Node::recreateWithSymRef(child, comp()->il.opCodeForIndirectLoad(child->getDataType()), shadow);412child->setAndIncChild(0, addrNode);413}414415return true;416}417418bool TR_DynamicLiteralPool::transformStaticSymRefToIndirectLoad(TR::TreeTop * tt, TR::Node *parent, TR::Node * & child)419{420// Only transform direct references421if (child->getOpCode().isIndirect())422return false;423424TR::SymbolReference * childSymRef = child->getSymbolReference();425//childSymRef->setFromLiteralPool();426TR::ILOpCode childOpcode=child->getOpCode();427TR::ILOpCodes childOpcodeValue=child->getOpCodeValue();428429if (childOpcodeValue==TR::loadaddr)430{431return false;432}433else434{435TR::SymbolReference *intChildShadow = NULL;436437if (childSymRef->isUnresolved())438{439if (cg()->supportsDirectIntegralLoadStoresFromLiteralPool())440{441return false;442}443444childSymRef->setFromLiteralPool();445446if (performTransformation(comp(), "%s unresolved static ref for node %p (%s)\n", optDetailString(), child, child->getOpCode().getName()))447{448_changed = true;449intChildShadow = getSymRefTab()->findOrCreateGenericIntShadowSymbolReference(0);450}451else452{453return false;454}455}456else457{458return false;459}460461intChildShadow->setFromLiteralPool();462getSymRefTab()->aliasBuilder.setLitPoolGenericIntShadowHasBeenCreated();463464TR::Node * loadLiteralFromThePool = TR::Node::createWithSymRef(TR::aloadi, 1, 1, getAloadFromCurrentBlock(child), childSymRef);465loadLiteralFromThePool->getSymbol()->setNotCollected();466if (childOpcodeValue==TR::awrtbar)467{468child->getFirstChild()->decReferenceCount();469child->getSecondChild()->decReferenceCount();470child = TR::Node::create(TR::awrtbari, 3, loadLiteralFromThePool, child->getFirstChild(), child->getSecondChild());471if (parent)472parent->setAndIncChild(0, child);473else474tt->setNode(child);475}476else477{478//TR::DataType type = childSymRef->getSymbol()->castToStaticSymbol()->getDataType();479TR::DataType type = child->getDataType();480if (childOpcode.isStore())481{482child->setSecond(child->getFirstChild());483TR::Node::recreate(child, comp()->il.opCodeForIndirectStore(type));484}485else if (childOpcode.isLoad())486{487TR::Node::recreate(child, comp()->il.opCodeForIndirectLoad(type));488}489else490{491TR_ASSERT(0,"not Load or Store, what is it ?\n");492}493child->setAndIncChild(0, loadLiteralFromThePool);494child->setNumChildren(child->getNumChildren()+1);495}496child->setSymbolReference(intChildShadow);497498dumpOptDetails(comp(), "created TR::aloadi %p from child %p\n", loadLiteralFromThePool, child);499}500501return true;502}503504bool TR_DynamicLiteralPool::addNewAloadChild(TR::Node *node)505{506if (!performTransformation(comp(), "%s creating new aload child for node %p (%s) %p \n", optDetailString(),node,node->getOpCode().getName()))507return false;508_changed = true;509node->setAndIncChild(node->getNumChildren(),getAloadFromCurrentBlock(node));510node->setNumChildren(node->getNumChildren()+1);511return true;512}513514515bool TR_DynamicLiteralPool::handleNodeUsingVMThread(TR::TreeTop * tt, TR::Node *parent, TR::Node *node, vcount_t visitCount)516{517/*518if (node->getOpCode().isLoadVarOrStore())519{520TR::SymbolReference *symRef = node->getSymbolReference();521if (symRef->isUnresolved())522{523}524else525{526if (symRef->getSymbol()->isMethodMetaData())527{528TR_ASSERT(node->getOpCode().isDirect(), "Load/store from meta data should use a direct opcode\n");529TR::SymbolReference *metaDataShadow = getSymRefTab()->findOrCreateGenericIntShadowSymbolReference(symRef->getOffset());530TR::Node * loadVMThreadFromTheStack = getVMThreadAloadFromCurrentBlock(node);531TR::DataType type = node->getDataType();532if (node->getOpCode().isStore())533{534node->setSecond(node->getFirstChild());535TR::Node::recreate(node, comp()->il.opCodeForIndirectStore(type));536}537else if (node->getOpCode().isLoad())538{539TR::Node::recreate(node, comp()->il.opCodeForIndirectLoad(type));540}541else542{543TR_ASSERT(0,"not Load or Store, what is it ?\n");544}545node->setAndIncChild(0, loadVMThreadFromTheStack);546node->setNumChildren(node->getNumChildren()+1);547node->setSymbolReference(metaDataShadow);548}549550if (node->getOpCode().isWrtBar())551{552}553}554}555*/556557return true;558}559560561bool TR_DynamicLiteralPool::handleNodeUsingSystemStack(TR::TreeTop * tt, TR::Node *parent, TR::Node *node, vcount_t visitCount)562{563return true;564}565566567TR::SymbolReference * getVMThreadSym()568{569return NULL;570}571572TR::Node *TR_DynamicLiteralPool::getVMThreadAloadFromCurrentBlock(TR::Node *parent)573{574if (_vmThreadAloadFromCurrentBlock==NULL)575{576setVMThreadAloadFromCurrentBlock(TR::Node::createWithSymRef(parent, TR::aload, 0, getVMThreadSym()));577dumpOptDetails(comp(), "New VM thread aload needed, it is: %p!\n", _vmThreadAloadFromCurrentBlock);578}579else580{581dumpOptDetails(comp(), "Can re-use VM thread aload %p!\n",_vmThreadAloadFromCurrentBlock);582}583return _vmThreadAloadFromCurrentBlock;584}585586const char *587TR_DynamicLiteralPool::optDetailString() const throw()588{589return "O^O DYNAMIC LITERAL POOL: ";590}591592593