Path: blob/master/runtime/compiler/optimizer/J9CFGSimplifier.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2019, 2020 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 "compile/Method.hpp"23#include "optimizer/CFGSimplifier.hpp"24#include "optimizer/Optimization_inlines.hpp"25#include "optimizer/TransformUtil.hpp"26#include "il/Block.hpp"27#include "il/Node.hpp"28#include "il/Node_inlines.hpp"29#include "il/StaticSymbol.hpp"30#include "il/Symbol.hpp"3132#define OPT_DETAILS "O^O CFG SIMPLIFICATION: "3334bool J9::CFGSimplifier::simplifyIfPatterns(bool needToDuplicateTree)35{36static char *enableCFGSimplification = feGetEnv("TR_enableCFGSimplificaiton");37if (enableCFGSimplification == NULL)38return false;3940return OMR::CFGSimplifier::simplifyIfPatterns(needToDuplicateTree)41|| simplifyResolvedRequireNonNull(needToDuplicateTree)42|| simplifyUnresolvedRequireNonNull(needToDuplicateTree)43;44}4546// Look for pattern of the form:47//48// ifacmpeq block_A49// ... some ref50// aconst NULL51//52// OR53//54// ifacmpne block_A55// ... some ref56// aconst NULL57//58// Where block_A looks like:59// ResolveCHK60// loadaddr61// treetop62// new63// => loadaddr64// ResolveAndNULLCHK65// call java/lang/NullPointerException.<init>();66// => new67// NULLCHK68// athrow69// => new7071bool J9::CFGSimplifier::simplifyUnresolvedRequireNonNull(bool needToDuplicateTree)72{73static char *disableSimplifyExplicitNULLTest = feGetEnv("TR_disableSimplifyExplicitNULLTest");74static char *disableSimplifyUnresolvedRequireNonNull = feGetEnv("TR_disableSimplifyUnresolvedRequireNonNull");75if (disableSimplifyExplicitNULLTest != NULL || disableSimplifyUnresolvedRequireNonNull != NULL)76return false;7778if (comp()->getOSRMode() == TR::involuntaryOSR)79return false;8081if (trace())82traceMsg(comp(), "Start simplifyUnresolvedRequireNonNull\n");8384// This block must end in an ifacmpeq or ifacmpne against aconst NULLa85TR::TreeTop *compareTreeTop = getLastRealTreetop(_block);86TR::Node *compareNode = compareTreeTop->getNode();87if (compareNode->getOpCodeValue() != TR::ifacmpeq88&& compareNode->getOpCodeValue() != TR::ifacmpne)89return false;9091if (trace())92traceMsg(comp(), " Found an ifacmp[eq/ne] n%dn\n", compareNode->getGlobalIndex());9394if (compareNode->getSecondChild()->getOpCodeValue() != TR::aconst95|| compareNode->getSecondChild()->getAddress() != 0)96return false;9798// _next1 is fall through so grab the block where the value is NULL99TR::Block *nullBlock = compareNode->getOpCodeValue() == TR::ifacmpeq ? _next2 : _next1;100TR::Block *nonnullBlock = compareNode->getOpCodeValue() == TR::ifacmpeq ? _next1 : _next2;101102if (trace())103traceMsg(comp(), " Matched nullBlock %d\n", nullBlock->getNumber());104105TR::TreeTop *nullBlockCursor = nullBlock->getEntry()->getNextTreeTop();106107if (nullBlockCursor->getNode()->getOpCodeValue() != TR::ResolveCHK108|| nullBlockCursor->getNode()->getFirstChild()->getOpCodeValue() != TR::loadaddr)109return false;110111if (trace())112traceMsg(comp(), " Match ResolveCHK of loadaddr\n");113114TR::Node *loadaddr = nullBlockCursor->getNode()->getFirstChild();115nullBlockCursor = nullBlockCursor->getNextTreeTop();116117if (nullBlockCursor->getNode()->getOpCodeValue() != TR::treetop118|| nullBlockCursor->getNode()->getFirstChild()->getOpCodeValue() != TR::New119|| nullBlockCursor->getNode()->getFirstChild()->getFirstChild() != loadaddr)120return false;121122TR::Node *exceptionNode = nullBlockCursor->getNode()->getFirstChild();123124if (trace())125traceMsg(comp(), " Matched new of loadaddr\n");126127nullBlockCursor = nullBlockCursor->getNextTreeTop();128129// optionally match pending push store130if (nullBlockCursor->getNode()->getOpCodeValue() == TR::astore131&& nullBlockCursor->getNode()->getFirstChild() == exceptionNode132&& nullBlockCursor->getNode()->getSymbol()->isPendingPush())133nullBlockCursor = nullBlockCursor->getNextTreeTop();134135if (nullBlockCursor->getNode()->getOpCodeValue() != TR::ResolveAndNULLCHK136|| nullBlockCursor->getNode()->getFirstChild()->getOpCodeValue() != TR::call137|| nullBlockCursor->getNode()->getFirstChild()->getFirstChild() != exceptionNode)138return false;139140TR::Node *initCall = nullBlockCursor->getNode()->getFirstChild();141142if (trace())143traceMsg(comp(), " Matched call node %d\n", initCall->getGlobalIndex());144145if (!initCall->getSymbolReference()->isUnresolved())146return false;147148TR::Method *calleeMethod = initCall->getSymbol()->castToMethodSymbol()->getMethod();149if (trace())150traceMsg(comp(), " Matched calleeMethod %s %s %s\n", calleeMethod->classNameChars(), calleeMethod->nameChars(), calleeMethod->signatureChars());151if (strncmp(calleeMethod->nameChars(), "<init>", 6) != 0152|| strncmp(calleeMethod->classNameChars(), "java/lang/NullPointerException", 30) != 0153|| strncmp(calleeMethod->signatureChars(), "()V", 3) != 0)154return false;155156157if (trace())158traceMsg(comp(), " Matched NPE init\n");159160nullBlockCursor = nullBlockCursor->getNextTreeTop();161if ((nullBlockCursor->getNode()->getOpCodeValue() != TR::NULLCHK162&& nullBlockCursor->getNode()->getOpCodeValue() != TR::treetop)163|| nullBlockCursor->getNode()->getFirstChild()->getOpCodeValue() != TR::athrow164|| nullBlockCursor->getNode()->getFirstChild()->getFirstChild() != exceptionNode)165return false;166167if (trace())168traceMsg(comp(), " Matched throw\n");169170TR::Node *throwNode = nullBlockCursor->getNode()->getFirstChild();171172nullBlockCursor = nullBlockCursor->getNextTreeTop();173if (nullBlockCursor != nullBlock->getExit())174return false;175176if (!performTransformation(comp(), "%sReplace ifacmpeq/ifacmpne of NULL node [%p] to throw of an NPE exception with NULLCHK\n", OPT_DETAILS, compareNode))177return false;178179_cfg->invalidateStructure();180181TR::DebugCounter::incStaticDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "cfgSimpNULLCHK/unresolvedNonNull/(%s)", comp()->signature()));182183TR::Block *checkBlock = _block;184if (hasExceptionPoint(_block, compareTreeTop))185checkBlock = _block->split(compareTreeTop, _cfg, true, false);186187if (!nullBlock->getExceptionSuccessors().empty())188{189for (auto itr = nullBlock->getExceptionSuccessors().begin(), end = nullBlock->getExceptionSuccessors().end(); itr != end; ++itr)190{191_cfg->addExceptionEdge(checkBlock, (*itr)->getTo());192}193}194195TR::Node *passthroughNode = TR::Node::create(throwNode, TR::PassThrough, 1);196passthroughNode->setAndIncChild(0, compareNode->getFirstChild());197TR::SymbolReference *symRef = comp()->getSymRefTab()->findOrCreateNullCheckSymbolRef(comp()->getMethodSymbol());198TR::Node *nullchkNode = TR::Node::createWithSymRef(TR::NULLCHK, 1, 1, passthroughNode, symRef);199if (trace())200traceMsg(comp(), "End simplifyUnresolvedRequireNonNull. Generated NULLCHK node n%dn\n", nullchkNode->getGlobalIndex());201TR::TreeTop *nullchkTree = TR::TreeTop::create(comp(), nullchkNode);202checkBlock->getEntry()->insertAfter(nullchkTree);203204_cfg->removeEdge(checkBlock, nullBlock);205TR::TransformUtil::removeTree(comp(), compareTreeTop);206207if (checkBlock->getNextBlock() != nonnullBlock)208{209TR::Node *gotoNode = TR::Node::create(nullchkNode, TR::Goto, 0);210gotoNode->setBranchDestination(nonnullBlock->getEntry());211checkBlock->append(TR::TreeTop::create(comp(), gotoNode));212}213214return true;215}216217// Look for pattern of the form:218//219// ifacmpeq block_A220// ... some ref221// aconst NULL222//223// OR224//225// ifacmpne block_A226// ... some ref227// aconst NULL228//229// Where block_A looks like:230// treetop231// new232// loadaddr java/lang/NullPointerException233// treetop | NULLCHK234// call java/lang/NullPointerException.<init>();235// => new236// treetop | NULLCHK237// athrow238// => new239//240// Replace the branch with a NULLCHK PassThrough of some ref241//242bool J9::CFGSimplifier::simplifyResolvedRequireNonNull(bool needToDuplicateTree)243{244static char *disableSimplifyExplicitNULLTest = feGetEnv("TR_disableSimplifyExplicitNULLTest");245static char *disableSimplifyResolvedRequireNonNull = feGetEnv("TR_disableSimplifyResolvedRequireNonNull");246if (disableSimplifyExplicitNULLTest != NULL || disableSimplifyResolvedRequireNonNull != NULL)247return false;248249if (comp()->getOSRMode() == TR::involuntaryOSR)250return false;251252if (trace())253traceMsg(comp(), "Start simplifyResolvedRequireNonNull\n");254255// This block must end in an ifacmpeq or ifacmpne against aconst NULL256TR::TreeTop *compareTreeTop = getLastRealTreetop(_block);257TR::Node *compareNode = compareTreeTop->getNode();258if (compareNode->getOpCodeValue() != TR::ifacmpeq259&& compareNode->getOpCodeValue() != TR::ifacmpne)260return false;261262if (trace())263traceMsg(comp(), " Found an ifacmp[eq/ne] n%dn\n", compareNode->getGlobalIndex());264265if (compareNode->getSecondChild()->getOpCodeValue() != TR::aconst266|| compareNode->getSecondChild()->getAddress() != 0)267return false;268269// _next1 is fall through so grab the block where the value is NULL270TR::Block *nullBlock = compareNode->getOpCodeValue() == TR::ifacmpeq ? _next2 : _next1;271TR::Block *nonnullBlock = compareNode->getOpCodeValue() == TR::ifacmpeq ? _next1 : _next2;272273traceMsg(comp(), " Found nullBlock %d\n", nullBlock->getNumber());274275TR::TreeTop *nullBlockCursor = nullBlock->getEntry()->getNextTreeTop();276if (nullBlockCursor->getNode()->getOpCodeValue() != TR::treetop277|| nullBlockCursor->getNode()->getFirstChild()->getOpCodeValue() != TR::New278|| nullBlockCursor->getNode()->getFirstChild()->getFirstChild()->getOpCodeValue() != TR::loadaddr)279return false;280281if (trace())282traceMsg(comp(), " Matched new tree\n");283284TR::Node *exceptionNode = nullBlockCursor->getNode()->getFirstChild();285TR::Node *loadaddr = nullBlockCursor->getNode()->getFirstChild()->getFirstChild();286// check for java/lang/NullPointerException as the loadaddr287TR_OpaqueClassBlock *NPEclazz = comp()->fej9()->getSystemClassFromClassName("java/lang/NullPointerException", strlen("java/lang/NullPointerException"));288if (loadaddr->getSymbolReference()->isUnresolved()289|| loadaddr->getSymbolReference()->getSymbol()->castToStaticSymbol()->getStaticAddress() != NPEclazz)290return false;291292if (trace())293traceMsg(comp(), " Matched new tree class\n");294295nullBlockCursor = nullBlockCursor->getNextTreeTop();296297// optionally match pending push store298if (nullBlockCursor->getNode()->getOpCodeValue() == TR::astore299&& nullBlockCursor->getNode()->getFirstChild() == exceptionNode300&& nullBlockCursor->getNode()->getSymbol()->isPendingPush())301nullBlockCursor = nullBlockCursor->getNextTreeTop();302303if ((nullBlockCursor->getNode()->getOpCodeValue() != TR::treetop304&& nullBlockCursor->getNode()->getOpCodeValue() != TR::NULLCHK)305|| nullBlockCursor->getNode()->getFirstChild()->getOpCodeValue() != TR::call306|| nullBlockCursor->getNode()->getFirstChild()->getFirstChild() != exceptionNode)307return false;308309if (trace())310traceMsg(comp(), " Matched exceptionNode\n");311312TR::Node *initCall = nullBlockCursor->getNode()->getFirstChild();313if (initCall->getSymbolReference()->isUnresolved())314return false;315316TR_ResolvedMethod *calleeMethod = initCall->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod();317if (trace())318traceMsg(comp(), " Matched calleeMethod %s %s %s\n", calleeMethod->classNameChars(), calleeMethod->nameChars(), calleeMethod->signatureChars());319if (strncmp(calleeMethod->nameChars(), "<init>", 6) != 0320|| strncmp(calleeMethod->classNameChars(), "java/lang/Throwable", 19) != 0321|| strncmp(calleeMethod->signatureChars(), "()V", 3) != 0)322return false;323324if (trace())325traceMsg(comp(), " Matched exceptionNode call\n");326327nullBlockCursor = nullBlockCursor->getNextTreeTop();328if ((nullBlockCursor->getNode()->getOpCodeValue() != TR::treetop329&& nullBlockCursor->getNode()->getOpCodeValue() != TR::NULLCHK)330|| nullBlockCursor->getNode()->getFirstChild()->getOpCodeValue() != TR::athrow331|| nullBlockCursor->getNode()->getFirstChild()->getFirstChild() != exceptionNode)332return false;333334if (trace())335traceMsg(comp(), " Matched exception throw\n");336337TR::Node *throwNode = nullBlockCursor->getNode()->getFirstChild();338339nullBlockCursor = nullBlockCursor->getNextTreeTop();340if (nullBlockCursor != nullBlock->getExit())341return false;342343if (!performTransformation(comp(), "%sReplace ifacmpeq/ifacmpne of NULL node [%p] to throw of an NPE exception with NULLCHK\n", OPT_DETAILS, compareNode))344return false;345346_cfg->invalidateStructure();347348TR::DebugCounter::incStaticDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "cfgSimpNULLCHK/resolvedNonNull/(%s)", comp()->signature()));349350TR::Block *checkBlock = _block;351if (hasExceptionPoint(_block, compareTreeTop))352checkBlock = _block->split(compareTreeTop, _cfg, true, false);353354if (!nullBlock->getExceptionSuccessors().empty())355{356for (auto itr = nullBlock->getExceptionSuccessors().begin(), end = nullBlock->getExceptionSuccessors().end(); itr != end; ++itr)357{358_cfg->addExceptionEdge(checkBlock, (*itr)->getTo());359}360}361362TR::Node *passthroughNode = TR::Node::create(throwNode, TR::PassThrough, 1);363passthroughNode->setAndIncChild(0, compareNode->getFirstChild());364TR::SymbolReference *symRef = comp()->getSymRefTab()->findOrCreateNullCheckSymbolRef(comp()->getMethodSymbol());365TR::Node *nullchkNode = TR::Node::createWithSymRef(TR::NULLCHK, 1, 1, passthroughNode, symRef);366if (trace())367traceMsg(comp(), "End simplifyResolvedRequireNonNull. Generated NULLCHK node n%dn\n", nullchkNode->getGlobalIndex());368TR::TreeTop *nullchkTree = TR::TreeTop::create(comp(), nullchkNode);369checkBlock->getEntry()->insertAfter(nullchkTree);370371_cfg->removeEdge(checkBlock, nullBlock);372TR::TransformUtil::removeTree(comp(), compareTreeTop);373374if (checkBlock->getNextBlock() != nonnullBlock)375{376TR::Node *gotoNode = TR::Node::create(nullchkNode, TR::Goto, 0);377gotoNode->setBranchDestination(nonnullBlock->getEntry());378checkBlock->append(TR::TreeTop::create(comp(), gotoNode));379}380381return true;382}383384385