Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/optimizer/AllocationSinking.cpp
6000 views
1
/*******************************************************************************
2
* Copyright (c) 2000, 2020 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* 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-exception
21
*******************************************************************************/
22
23
#include "optimizer/AllocationSinking.hpp"
24
25
#include <limits.h>
26
#include <math.h>
27
#include <stddef.h>
28
#include <stdint.h>
29
#include <stdio.h>
30
#include <stdlib.h>
31
#include <string.h>
32
#include "codegen/CodeGenerator.hpp"
33
#include "env/FrontEnd.hpp"
34
#include "compile/Compilation.hpp"
35
#include "compile/Method.hpp"
36
#include "control/Options.hpp"
37
#include "control/Options_inlines.hpp"
38
#include "control/Recompilation.hpp"
39
#include "control/RecompilationInfo.hpp"
40
#include "env/StackMemoryRegion.hpp"
41
#include "env/CompilerEnv.hpp"
42
#include "env/TRMemory.hpp"
43
#include "env/jittypes.h"
44
#include "il/Block.hpp"
45
#include "il/DataTypes.hpp"
46
#include "il/ILOpCodes.hpp"
47
#include "il/ILOps.hpp"
48
#include "il/MethodSymbol.hpp"
49
#include "il/Node.hpp"
50
#include "il/NodePool.hpp"
51
#include "il/Node_inlines.hpp"
52
#include "il/ParameterSymbol.hpp"
53
#include "il/ResolvedMethodSymbol.hpp"
54
#include "il/StaticSymbol.hpp"
55
#include "il/Symbol.hpp"
56
#include "il/SymbolReference.hpp"
57
#include "il/TreeTop.hpp"
58
#include "il/TreeTop_inlines.hpp"
59
#include "infra/Assert.hpp"
60
#include "infra/Cfg.hpp"
61
#include "infra/ILWalk.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 "ras/Debug.hpp"
70
71
72
int32_t TR_AllocationSinking::perform()
73
{
74
if (comp()->getOptions()->realTimeGC()) // memory area can be changed by the arg eval call, so better not disturb things
75
return 0;
76
77
// Note: if the evaluation of constructor arguments contains control flow (ie. a select)
78
// then the "new" and ctor call will be in different blocks, and this opt won't have the
79
// desired effect.
80
81
// We change the trees as we scan, which is often slightly gross, but in
82
// this case it works reasonably well; because we only move trees downward,
83
// if we scan upward, we will see the right things at the right time.
84
//
85
// Because trees may move as we go, we have to remember where to continue scanning.
86
//
87
TR::TreeTop *allocScanPoint;
88
89
for (TR::TreeTop *allocTree = comp()->findLastTree(); allocTree; allocTree = allocScanPoint)
90
{
91
allocScanPoint = allocTree->getPrevTreeTop();
92
TR::Node *allocation;
93
if (allocTree->getNode()->getOpCodeValue() == TR::treetop && (allocation=allocTree->getNode()->getFirstChild())->getOpCodeValue() == TR::New)
94
{
95
if (trace())
96
{
97
traceMsg(comp(), "Found allocation %s\n", comp()->getDebug()->getName(allocation));
98
printf("Allocation Sinking found allocation %s in %s\n", comp()->getDebug()->getName(allocation), comp()->signature());
99
}
100
101
// Scan down for the first actual use of this new
102
//
103
TR::TreeTop *flushToSink = NULL;
104
vcount_t visitCount = comp()->incVisitCount();
105
for (TR::TreeTop *useTree = allocTree->getNextTreeTop(); useTree && (useTree->getNode()->getOpCodeValue() != TR::BBEnd); useTree = useTree->getNextTreeTop())
106
{
107
TR::Node *useNode = useTree->getNode();
108
if (useNode->getOpCodeValue() == TR::allocationFence && useNode->getAllocation() == allocation)
109
{
110
// This flush is only protecting this allocation, so we can move it down too
111
//
112
flushToSink = useTree;
113
if (trace())
114
traceMsg(comp(), " Sinking flush %s along with %s\n",
115
comp()->getDebug()->getName(flushToSink->getNode()),
116
comp()->getDebug()->getName(allocation));
117
}
118
else if (
119
(useTree->getNode()->containsNode(allocation, visitCount))
120
|| (useNode->getOpCodeValue() == TR::allocationFence && useNode->getAllocation() == NULL) // found a flush that *might* be protecting this allocation and others; time to give up
121
|| (trace() && !performTransformation(comp(), "O^O ALLOCATION SINKING: Moving allocation %s down past %s\n",
122
comp()->getDebug()->getName(allocation), comp()->getDebug()->getName(useTree->getNode())))
123
){
124
if (allocTree->getNextTreeTop() == useTree)
125
{
126
if (trace())
127
traceMsg(comp(), " Allocation %s is used immediately in %s; no sinking opportunity\n",
128
comp()->getDebug()->getName(allocation),
129
comp()->getDebug()->getName(useTree->getNode()));
130
break;
131
}
132
{
133
// Allocation Sinking is skipped when the class is unresolved.
134
TR::Node* nodeNew = allocTree->getNode()->getFirstChild();
135
TR_ASSERT(nodeNew, "Local Opts, expected the first child of a treetop not to be null");
136
TR_ASSERT(nodeNew->getOpCode().isNew(), "Local Opts, expected the first child of a treetop to be a new");
137
TR_ASSERT(nodeNew->getFirstChild(), "Local Opts, expected the first child of a new not to be null");
138
TR_ASSERT(nodeNew->getFirstChild()->getOpCode().isLoadAddr(), "Local Opts, expected the first child of a new to be a loadaddr");
139
if (nodeNew->getFirstChild()->hasUnresolvedSymbolReference())
140
{
141
continue;
142
}
143
}
144
// Move the "new" right before the first use / flush
145
// (Note that we skip the performTransformation here if trace()
146
// is on because it would interfere with the finer-grained one.)
147
//
148
if ( trace()
149
|| (!comp()->ilGenTrace() || performTransformation(comp(), "O^O ALLOCATION SINKING: Moving allocation %s down to %s\n",
150
comp()->getDebug()->getName(allocation), comp()->getDebug()->getName(useTree->getNode())))
151
){
152
allocTree->unlink(false);
153
useTree->insertBefore(allocTree);
154
if (flushToSink)
155
{
156
flushToSink->unlink(false);
157
useTree->insertBefore(flushToSink);
158
if (trace())
159
traceMsg(comp(), " Sank flush %s along with allocation %s\n", comp()->getDebug()->getName(flushToSink->getNode()), comp()->getDebug()->getName(allocation));
160
}
161
}
162
break;
163
}
164
}
165
}
166
}
167
168
return 0;
169
}
170
171
const char *
172
TR_AllocationSinking::optDetailString() const throw()
173
{
174
return "O^O ALLOCATION SINKING: ";
175
}
176
177