Path: blob/master/runtime/compiler/optimizer/AllocationSinking.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2000, 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 "optimizer/AllocationSinking.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 "control/Options.hpp"36#include "control/Options_inlines.hpp"37#include "control/Recompilation.hpp"38#include "control/RecompilationInfo.hpp"39#include "env/StackMemoryRegion.hpp"40#include "env/CompilerEnv.hpp"41#include "env/TRMemory.hpp"42#include "env/jittypes.h"43#include "il/Block.hpp"44#include "il/DataTypes.hpp"45#include "il/ILOpCodes.hpp"46#include "il/ILOps.hpp"47#include "il/MethodSymbol.hpp"48#include "il/Node.hpp"49#include "il/NodePool.hpp"50#include "il/Node_inlines.hpp"51#include "il/ParameterSymbol.hpp"52#include "il/ResolvedMethodSymbol.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/TRCfgEdge.hpp"62#include "infra/TRCfgNode.hpp"63#include "optimizer/Optimization.hpp"64#include "optimizer/Optimization_inlines.hpp"65#include "optimizer/OptimizationManager.hpp"66#include "optimizer/Optimizations.hpp"67#include "optimizer/Optimizer.hpp"68#include "ras/Debug.hpp"697071int32_t TR_AllocationSinking::perform()72{73if (comp()->getOptions()->realTimeGC()) // memory area can be changed by the arg eval call, so better not disturb things74return 0;7576// Note: if the evaluation of constructor arguments contains control flow (ie. a select)77// then the "new" and ctor call will be in different blocks, and this opt won't have the78// desired effect.7980// We change the trees as we scan, which is often slightly gross, but in81// this case it works reasonably well; because we only move trees downward,82// if we scan upward, we will see the right things at the right time.83//84// Because trees may move as we go, we have to remember where to continue scanning.85//86TR::TreeTop *allocScanPoint;8788for (TR::TreeTop *allocTree = comp()->findLastTree(); allocTree; allocTree = allocScanPoint)89{90allocScanPoint = allocTree->getPrevTreeTop();91TR::Node *allocation;92if (allocTree->getNode()->getOpCodeValue() == TR::treetop && (allocation=allocTree->getNode()->getFirstChild())->getOpCodeValue() == TR::New)93{94if (trace())95{96traceMsg(comp(), "Found allocation %s\n", comp()->getDebug()->getName(allocation));97printf("Allocation Sinking found allocation %s in %s\n", comp()->getDebug()->getName(allocation), comp()->signature());98}99100// Scan down for the first actual use of this new101//102TR::TreeTop *flushToSink = NULL;103vcount_t visitCount = comp()->incVisitCount();104for (TR::TreeTop *useTree = allocTree->getNextTreeTop(); useTree && (useTree->getNode()->getOpCodeValue() != TR::BBEnd); useTree = useTree->getNextTreeTop())105{106TR::Node *useNode = useTree->getNode();107if (useNode->getOpCodeValue() == TR::allocationFence && useNode->getAllocation() == allocation)108{109// This flush is only protecting this allocation, so we can move it down too110//111flushToSink = useTree;112if (trace())113traceMsg(comp(), " Sinking flush %s along with %s\n",114comp()->getDebug()->getName(flushToSink->getNode()),115comp()->getDebug()->getName(allocation));116}117else if (118(useTree->getNode()->containsNode(allocation, visitCount))119|| (useNode->getOpCodeValue() == TR::allocationFence && useNode->getAllocation() == NULL) // found a flush that *might* be protecting this allocation and others; time to give up120|| (trace() && !performTransformation(comp(), "O^O ALLOCATION SINKING: Moving allocation %s down past %s\n",121comp()->getDebug()->getName(allocation), comp()->getDebug()->getName(useTree->getNode())))122){123if (allocTree->getNextTreeTop() == useTree)124{125if (trace())126traceMsg(comp(), " Allocation %s is used immediately in %s; no sinking opportunity\n",127comp()->getDebug()->getName(allocation),128comp()->getDebug()->getName(useTree->getNode()));129break;130}131{132// Allocation Sinking is skipped when the class is unresolved.133TR::Node* nodeNew = allocTree->getNode()->getFirstChild();134TR_ASSERT(nodeNew, "Local Opts, expected the first child of a treetop not to be null");135TR_ASSERT(nodeNew->getOpCode().isNew(), "Local Opts, expected the first child of a treetop to be a new");136TR_ASSERT(nodeNew->getFirstChild(), "Local Opts, expected the first child of a new not to be null");137TR_ASSERT(nodeNew->getFirstChild()->getOpCode().isLoadAddr(), "Local Opts, expected the first child of a new to be a loadaddr");138if (nodeNew->getFirstChild()->hasUnresolvedSymbolReference())139{140continue;141}142}143// Move the "new" right before the first use / flush144// (Note that we skip the performTransformation here if trace()145// is on because it would interfere with the finer-grained one.)146//147if ( trace()148|| (!comp()->ilGenTrace() || performTransformation(comp(), "O^O ALLOCATION SINKING: Moving allocation %s down to %s\n",149comp()->getDebug()->getName(allocation), comp()->getDebug()->getName(useTree->getNode())))150){151allocTree->unlink(false);152useTree->insertBefore(allocTree);153if (flushToSink)154{155flushToSink->unlink(false);156useTree->insertBefore(flushToSink);157if (trace())158traceMsg(comp(), " Sank flush %s along with allocation %s\n", comp()->getDebug()->getName(flushToSink->getNode()), comp()->getDebug()->getName(allocation));159}160}161break;162}163}164}165}166167return 0;168}169170const char *171TR_AllocationSinking::optDetailString() const throw()172{173return "O^O ALLOCATION SINKING: ";174}175176177