-
Notifications
You must be signed in to change notification settings - Fork 139
/
Copy pathByteCodeIteratorWithState.hpp
434 lines (373 loc) · 16.1 KB
/
ByteCodeIteratorWithState.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
/*******************************************************************************
* Copyright IBM Corp. and others 2000
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution
* and is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License, v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception [1] and GNU General Public
* License, version 2 with the OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] https://openjdk.org/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
*******************************************************************************/
#include <stdint.h>
#include <string.h>
#include "env/FrontEnd.hpp"
#include "compile/Compilation.hpp"
#include "control/Options.hpp"
#include "control/Options_inlines.hpp"
#include "infra/deque.hpp"
#include "env/TRMemory.hpp"
#include "il/Block.hpp"
#include "infra/Assert.hpp"
#include "infra/Flags.hpp"
#include "infra/Link.hpp"
#include "infra/Stack.hpp"
#include "optimizer/Optimizations.hpp"
#include "env/IO.hpp"
namespace TR { class ResolvedMethodSymbol; }
namespace TR { class TreeTop; }
template<typename ByteCode,
ByteCode BCunknown,
class ByteCodeIterator,
typename OperandStackElementType> class TR_ByteCodeIteratorWithState : public ByteCodeIterator
{
public:
typedef TR_Stack<OperandStackElementType> ByteCodeStack;
TR_ByteCodeIteratorWithState(TR::ResolvedMethodSymbol *methodSym, TR::Compilation *comp)
: ByteCodeIterator(methodSym, comp),
_unimplementedOpcode(0),
_inExceptionHandler(false),
_stack(NULL),
_backwardBranches(),
_todoQueue(),
_stackTemps(comp->trMemory(), 20),
_tryCatchInfo(comp->allocator("IlGen"))
{
_printByteCodes = (comp->getOutFile() != NULL && comp->getOption(TR_TraceBC) && (comp->isOutermostMethod() || comp->getOption(TR_DebugInliner) || comp->trace(OMR::inlining)));
_cannotAttemptOSR = comp->getOption(TR_EnableOSR) && !comp->isPeekingMethod() && methodSym->cannotAttemptOSRDuring(comp->getCurrentInlinedSiteIndex(), comp);
}
void printByteCodes()
{
this->printByteCodePrologue();
for (ByteCode bc = this->first(); bc != BCunknown; bc = this->next())
this->printByteCode();
this->printByteCodeEpilogue();
}
protected:
enum ByteCodeWithStateFlags
{
inExceptionRange = 0x01,
generated = 0x02
};
/// used to create a worklist of bytecode indices to traverse
struct TodoIndex : TR_Link<TodoIndex>
{
TodoIndex(int32_t i) : _index(i) { }
int32_t _index;
};
/// used to store a list of edges between bytecode indices
struct IndexPair : TR_Link<IndexPair>
{
IndexPair(int32_t f, int32_t t) : _fromIndex(f), _toIndex(t) { }
int32_t _fromIndex, _toIndex;
};
void initialize()
{
uint32_t size = this->maxByteCodeIndex() + 5;
_flags = (flags8_t *) this->trMemory()->allocateStackMemory(size * sizeof(flags8_t));
_blocks = (TR::Block * *) this->trMemory()->allocateStackMemory(size * sizeof(TR::Block *));
_stacks = (ByteCodeStack * *) this->trMemory()->allocateStackMemory(size * sizeof(ByteCodeStack *));
memset(_flags, 0, size * sizeof(flags8_t));
memset(_blocks, 0, size * sizeof(TR::Block *));
memset(_stacks, 0, size * sizeof(ByteCodeStack *));
findAndMarkBranchTargets();
findAndMarkExceptionRanges();
genBBStart(0);
setupBBStartContext(0);
this->setIndex(0);
}
/// called for each control flow edge from bytecode at fromIndex, destination bytecode is fromIndex+relativeBranch
/// if it's a backward branch (relativeBranch < 0) then the edge is added to the _backwardBranches list
/// and some flags are updated on the method symbol to indicate it may have loops or, if appropriate, nested loops
/// finally, genBBStart is called for the destination bytecode to register that it is the start of a basic block
void markTarget(int32_t fromIndex, int32_t relativeBranch)
{
int32_t toIndex = fromIndex + relativeBranch;
if (relativeBranch < 0)
{
this->_methodSymbol->setMayHaveLoops(true);
IndexPair * ip, * prev = 0, * newIP = new (this->comp()->trStackMemory()) IndexPair(fromIndex, toIndex);
for (ip = _backwardBranches.getFirst(); ip; prev = ip, ip = ip->getNext())
{
TR_ASSERT(fromIndex >= ip->_fromIndex, "markTarget: fromIndex's aren't increasing?");
if (ip->_toIndex < toIndex || fromIndex == ip->_fromIndex)
break;
if (debug("onlyConsiderProperlyNestedBackwardBranches") && ip->_toIndex == toIndex)
break;
this->_methodSymbol->setMayHaveNestedLoops(true);
}
newIP->setNext(ip);
if (prev)
prev->setNext(newIP);
else
_backwardBranches.setFirst(newIP);
}
genBBStart(toIndex);
}
/// called to identify the branches and their targets in the method
/// causes the _blocks array to be filled in with the basic blocks of the method
void findAndMarkBranchTargets()
{
TR::Compilation *comp = this->comp();
if (debug("branchTargets"))
diagnostic("findAndMarkBranchTargets for %s\n", comp->signature());
aboutToFindBranchTargets();
for (ByteCode bc = this->first(); bc != BCunknown; bc = this->next())
{
if (_printByteCodes)
this->printByteCode();
int32_t i = this->bcIndex();
if (this->isBranch())
markTarget(i, this->branchDestination(i) - i);
markAnySpecialBranchTargets(bc);
}
finishedFindingBranchTargets();
}
/// any work that should be done before starting the search for branches and targets
virtual void aboutToFindBranchTargets()
{
if (_printByteCodes)
this->printByteCodePrologue();
}
/// analyze any bytecodes that don't look like branches but represent control flows and suggest basic block beginnings
virtual void markAnySpecialBranchTargets(ByteCode bc) { }
/// any work that should be done after all the branches and their targets have been found
virtual void finishedFindingBranchTargets()
{
if (_printByteCodes)
this->printByteCodeEpilogue();
}
/// update state when an exception range is identified
/// create all the appropriate basic blocks
/// initialize the summary list of try catch regions
/// mark bytecodes in the range as having a handler (inExceptionRange)
void markExceptionRange(int32_t index, int32_t start, int32_t end, int32_t handler, uint32_t type)
{
TR::Compilation *comp = this->comp();
if (_printByteCodes)
trfprintf(this->comp()->getOutFile(), "ExceptionRange: start [%8x] end [%8x] handler [%8x] type [%8x] \n", start, end, handler, type);
genBBStart(start);
genBBStart(end + 1);
genBBStart(handler);
TR_ASSERT(_tryCatchInfo.begin() + index == _tryCatchInfo.end(), "Unexpected insertion order");
_tryCatchInfo.insert(_tryCatchInfo.begin() + index, typename ByteCodeIterator::TryCatchInfo(start, end, handler, type));
for (int32_t j = start; j <= end; ++j)
setIsInExceptionRange(j);
}
/// language specifies how exception ranges are discovered
/// some languages (like Java) encode exception ranges as meta-data alongside the bytecodes
/// other languages need to discover exception ranges because they aren't specified explicitly by the bytecodes
virtual void findAndMarkExceptionRanges() = 0;
/// called when a bytecode index is the target of a branch so it needs to be the start of a basic block
/// determines to which basic block the nodes for a translated bytecode will go
void genBBStart(int32_t index)
{
if (!blocks(index))
{
blocks(index) = TR::Block::createEmptyBlock(this->comp());
blocks(index)->setByteCodeIndex(index, this->comp());
}
}
/// saveStack preserves the state of the operand stack at the end of a basic block or as needed within a block
/// operand stack slots are saved into locals; other blocks can then access the state of the operand stack by loading those locals
virtual void saveStack(int32_t) = 0;
/// called when bytecode index "index" has been identified as the target of a branch, so needs its own basic block
/// if queueTarget is true, target index added to the _todoQueue to make sure it is translated
/// genBBStart to create the basic block structure
/// saveStack to make sure the state of the operand stack is accessible at the beginning of the basic block associated with target
/// returns the TR::TreeTop to which new treetops in the target block should be appended
TR::TreeTop * genTarget(int32_t index, bool queueTarget = true)
{
if (queueTarget)
_todoQueue.append(new (this->comp()->trStackMemory()) TodoIndex(index));
genBBStart(index);
saveStack(index);
return blocks(index)->getEntry();
}
/// called at end of a basic block with _bcIndex set to the next target
/// returns with the next byte code index to translate at, which may not match the target provided
/// if that target block has already been generated
int32_t genBBEndAndBBStart()
{
genTarget(this->_bcIndex);
return findNextByteCodeToGen();
}
/// initializes the operand stack state for the given bytecode index, typically called at the beginning of a basic block
/// returns the bytecode index provided.
virtual int32_t setupBBStartContext(int32_t index)
{
if (_stacks[index] != NULL)
{
*_stack = *_stacks[index];
_stackTemps = *_stacks[index];
}
else
{
if (_stack)
_stack->clear();
_stackTemps.clear();
}
_block = blocks(index);
return index;
}
/// grabs the next basic block start from _todoQueue that has not been generated yet
/// once found, setupBBStartContext is called to ensure everything is ready to start translating bytecodes at that index
/// if nothing left to translate, returns _maxByteCode + 8 as a number bigger than the exit test for the simulation loop
int32_t findNextByteCodeToGen()
{
// find and setup the next bbStart context
//
TodoIndex * ti;
while (NULL != (ti = _todoQueue.pop()))
{
if (!isGenerated(ti->_index))
return setupBBStartContext(ti->_index);
}
return this->maxByteCodeIndex() + 8; // indicate that we're done
}
/// returns true if the bytecode index i is part of an exception range (try block)
bool isInExceptionRange(int32_t i)
{
return _flags[i].testAny(inExceptionRange);
}
/// remember that the bytecode index i is part of an exception range (try block)
void setIsInExceptionRange(int32_t i)
{
_flags[i].set(inExceptionRange);
}
/// returns true if the bytecode at index i has already been generated (translated to IR)
bool isGenerated(int32_t i)
{
return _flags[i].testAny(generated);
}
/// remember that the bytecode at index i has already been generated (translated to IR)
void setIsGenerated(int32_t i)
{
_flags[i].set(generated);
}
/// return the basic block that starts at byte code index i
TR::Block * &blocks(int32_t i)
{
return _blocks[i];
}
/// return the i'th element in the operand stack (numbered from the bottom of the operand stack, not the top)
OperandStackElementType& node(uint32_t i)
{
return _stack->element(i);
}
/// return the top element on the operand stack
OperandStackElementType& top()
{
return topn(0);
}
/// return the top n-th element on the operand stack
OperandStackElementType& topn(uint32_t n)
{
return node(_stack->topIndex() - n);
}
/// return the top element of the operand stack and pop it off the operand stack
OperandStackElementType pop()
{
return _stack->pop();
}
/// pop n elements from the top of the stack
void popn(uint32_t n)
{
_stack->setSize(_stack->size() - n);
}
/// push the element onto the operand stack
void push(OperandStackElementType n)
{
_stack->push(n);
}
/// swap the top two elements of the operand stack
void swap()
{
_stack->swap();
}
/// sets the n'th element from the top to the new element e
void setn(int32_t n, OperandStackElementType e)
{
topn(n) = e;
}
/// duplicate the top of the operand stack
void dup()
{
dupn(1);
}
/// duplicate the top n elements of the operand stack
void dupn(int32_t n)
{
shift(n, n);
}
/// generic helper routine for shifting duplicates of existing operand stack elements to the top
/// first grow the stack by copyCount then shift part of the operand stack (from top) up to the new top
/// NOTE: if copyCount > shiftCount then (copyCount - shiftCount) elements above the top of the original operand stack will not be set
void shift(int32_t shiftCount, int32_t copyCount)
{
_stack->setSize(_stack->size() + copyCount);
for (int32_t i = 0; i < shiftCount; ++i)
node(_stack->topIndex() - i) = node(_stack->topIndex() - i - copyCount);
}
/// generic helper routine for shifting and then copying elements of the operand stack
/// first shifts operand stack by shiftCount, then copies the shifted elements underneath the shifted operand stack values
void shiftAndCopy(int32_t shiftCount, int32_t copyCount)
{
shift(shiftCount, copyCount);
for (int32_t i = 0; i < copyCount; ++i)
node(_stack->topIndex() - i - shiftCount) = node(_stack->topIndex() - i);
}
/// rotates "countArg" elements off the top to the bottom of the operand stack
/// Expected: -operand stack size <= countArg <= operand stack size
///
/// \warning Make sure you know what you're doing regarding pending push
/// temps or you'll mess up FSD because of this rotation
void rotate(int32_t countArg)
{
uint32_t count;
if (countArg < 0)
count = (uint32_t) (_stack->size() + countArg);
else
count = (uint32_t) countArg;
// Duplicate the entries that will wrap around to the cold end of the operand stack
uint32_t oldSize = _stack->size();
shift(oldSize, count);
// Move them to the cold end and then discard the duplicates
//
for (uint32_t i = 0; i < count; ++i)
node(i) = node(oldSize + i);
_stack->setSize(oldSize);
}
ByteCodeStack * _stack; ///< current operand stack
ByteCodeStack _stackTemps;
ByteCodeStack * * _stacks;
TR::Block * _block; ///< current block
TR::Block * * _blocks;
TR_LinkHeadAndTail<TodoIndex> _todoQueue;
TR_LinkHead<IndexPair> _backwardBranches;
bool _inExceptionHandler;
bool _printByteCodes;
bool _cannotAttemptOSR;
flags8_t * _flags;
uint8_t _unimplementedOpcode; ///< (255 if opcode unknown)
TR::deque<class ByteCodeIterator::TryCatchInfo> _tryCatchInfo;
};