Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/optimizer/InterpreterEmulator.hpp
6000 views
1
/*******************************************************************************
2
* Copyright (c) 2000, 2021 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
/*
24
* \class InterpreterEmulator
25
*
26
* \brief This class is a bytecode iterator in estimate code size (ECS) of inliner.
27
*
28
* \notes The iterator has statelss and with state modes.
29
*
30
* Stateless mode is the default mode and can be used to iterate
31
* through bytecodes in the method. This mode is currently used in the
32
* in ECS for \ref processBytecodeAndGenerateCFG for all methods and
33
* \ref findAndCreateCallsitesFromBytecodes when the target is not a methodhandle
34
* thunk archetype.
35
*
36
* With state mode is used to emulate the interpreter execution with
37
* an operand stack maintained during bytecode iteration to keep useful
38
* information like known object and constant integer so
39
* that inliner can make better decision when creating callsites. For
40
* example, inliner can avoid creating callsites on dead path
41
* \ref maintainStackForIf or can refine callee method based on known
42
* receiver info \ref refineResolvedCalleeForInvokestatic. Operands that
43
* can't be reasoned about are represented by a dummy operand \ref _unknownOperand
44
* which doesn't carry any extra information. Currently, with state mode only
45
* supports methodhandle thunk archetypes.
46
*/
47
48
#ifndef INTERPRETER_EMULATOR_INCL
49
#define INTERPRETER_EMULATOR_INCL
50
51
#include "compile/Compilation.hpp"
52
#include "env/TRMemory.hpp"
53
#include "il/Block.hpp"
54
#include "ilgen/ByteCodeIteratorWithState.hpp"
55
#include "ilgen/J9ByteCodeIterator.hpp"
56
#include "infra/String.hpp"
57
#include "optimizer/Inliner.hpp"
58
#include "optimizer/J9EstimateCodeSize.hpp"
59
#include "optimizer/J9Inliner.hpp"
60
61
class IconstOperand;
62
class KnownObjOperand;
63
class MutableCallsiteTargetOperand;
64
class FixedClassOperand;
65
class PreexistentObjectOperand;
66
class ObjectOperand;
67
class TR_PrexArgument;
68
69
/*
70
* \class Operand
71
*
72
* \brief represent an operand on the operand stack
73
*
74
* \note this is the most general operand which doesn't carry any specific information.
75
*/
76
class Operand
77
{
78
public:
79
TR_ALLOC(TR_Memory::EstimateCodeSize);
80
81
enum KnowledgeLevel { NONE, OBJECT, MUTABLE_CALLSITE_TARGET, PREEXISTENT, FIXED_CLASS, KNOWN_OBJECT, ICONST };
82
static const char* KnowledgeStrings[];
83
84
virtual IconstOperand* asIconst(){ return NULL;}
85
virtual KnownObjOperand *asKnownObject(){ return NULL;}
86
virtual FixedClassOperand *asFixedClassOperand(){ return NULL;}
87
virtual PreexistentObjectOperand *asPreexistentObjectOperand(){ return NULL;}
88
virtual ObjectOperand *asObjectOperand(){ return NULL;}
89
virtual MutableCallsiteTargetOperand* asMutableCallsiteTargetOperand(){ return NULL;}
90
virtual TR::KnownObjectTable::Index getKnownObjectIndex(){ return TR::KnownObjectTable::UNKNOWN;}
91
virtual char* getSignature(TR::Compilation *comp, TR_Memory *trMemory) {return NULL;}
92
virtual void printToString(TR::StringBuf *buf);
93
virtual KnowledgeLevel getKnowledgeLevel() { return NONE; }
94
Operand* merge(Operand* other);
95
virtual Operand* merge1(Operand* other);
96
};
97
98
class IconstOperand : public Operand
99
{
100
public:
101
TR_ALLOC(TR_Memory::EstimateCodeSize);
102
IconstOperand (int x): intValue(x) { }
103
virtual IconstOperand *asIconst() { return this;}
104
virtual void printToString(TR::StringBuf *buf);
105
int32_t intValue;
106
107
virtual KnowledgeLevel getKnowledgeLevel() { return ICONST; }
108
virtual Operand* merge1(Operand* other);
109
};
110
111
112
/*
113
* \class ObjectOperand
114
*
115
* \brief Represent a java object
116
*/
117
class ObjectOperand : public Operand
118
{
119
public:
120
TR_ALLOC(TR_Memory::EstimateCodeSize);
121
ObjectOperand(TR_OpaqueClassBlock* clazz = NULL):
122
_signature(NULL), _clazz(clazz) {}
123
virtual char* getSignature(TR::Compilation *comp, TR_Memory *trMemory);
124
virtual ObjectOperand *asObjectOperand(){ return this;}
125
virtual TR_OpaqueClassBlock* getClass() { return _clazz;}
126
virtual KnowledgeLevel getKnowledgeLevel() { return OBJECT; }
127
virtual Operand* merge1(Operand* other);
128
virtual void printToString(TR::StringBuf *buf);
129
130
protected:
131
char* _signature;
132
TR_OpaqueClassBlock* _clazz;
133
};
134
135
/*
136
* \class PreexistentObjectOperand
137
*
138
* \brief Represent an object that preexist before the compiled method, i.e. it is
139
* a parm of the compiled method.
140
*/
141
class PreexistentObjectOperand : public ObjectOperand
142
{
143
public:
144
TR_ALLOC(TR_Memory::EstimateCodeSize);
145
PreexistentObjectOperand(TR_OpaqueClassBlock* clazz):ObjectOperand(clazz){ }
146
virtual PreexistentObjectOperand *asPreexistentObjectOperand(){ return this;}
147
virtual KnowledgeLevel getKnowledgeLevel() { return PREEXISTENT; }
148
virtual Operand* merge1(Operand* other);
149
};
150
151
/*
152
* \class FixedClassOperand
153
*
154
* \brief An object with known type
155
*/
156
class FixedClassOperand : public ObjectOperand
157
{
158
public:
159
TR_ALLOC(TR_Memory::EstimateCodeSize);
160
FixedClassOperand(TR_OpaqueClassBlock* clazz):ObjectOperand(clazz){ }
161
virtual FixedClassOperand *asFixedClassOperand(){ return this;}
162
virtual KnowledgeLevel getKnowledgeLevel() { return FIXED_CLASS; }
163
virtual Operand* merge1(Operand* other);
164
};
165
166
/*
167
* \class KnownObjOperand
168
*
169
* \brief Represent an object with known identity at compile time
170
*/
171
class KnownObjOperand : public FixedClassOperand
172
{
173
public:
174
TR_ALLOC(TR_Memory::EstimateCodeSize);
175
KnownObjOperand(TR::KnownObjectTable::Index koi, TR_OpaqueClassBlock* clazz = NULL);
176
virtual KnownObjOperand *asKnownObject(){ return this;}
177
virtual FixedClassOperand *asFixedClassOperand();
178
virtual ObjectOperand *asObjectOperand();
179
virtual TR_OpaqueClassBlock* getClass();
180
virtual TR::KnownObjectTable::Index getKnownObjectIndex(){ return knownObjIndex;}
181
virtual KnowledgeLevel getKnowledgeLevel() { return KNOWN_OBJECT; }
182
virtual Operand* merge1(Operand* other);
183
virtual void printToString(TR::StringBuf *buf);
184
private:
185
TR::KnownObjectTable::Index knownObjIndex;
186
};
187
188
/*
189
* \class MutableCallsiteTargetOperand
190
*
191
* \note This class is used to support mutable callsite because both the methodhandle object
192
* and the mutable callsite needs to be tracked so that when creating \c TR_J9MutableCallSite
193
* the mutable callsite object can be set for the callsite even though it's really the
194
* methodhandle object that's on the operand stack.
195
*
196
* \see getReturnValue
197
* \see refineResolvedCalleeForInvokestatic
198
* \see visitInvokestatic
199
*/
200
class MutableCallsiteTargetOperand : public ObjectOperand
201
{
202
public:
203
TR_ALLOC(TR_Memory::EstimateCodeSize);
204
MutableCallsiteTargetOperand (TR::KnownObjectTable::Index methodHandleIndex, TR::KnownObjectTable::Index mutableCallsiteIndex):
205
methodHandleIndex(methodHandleIndex),
206
mutableCallsiteIndex(mutableCallsiteIndex){}
207
virtual MutableCallsiteTargetOperand* asMutableCallsiteTargetOperand(){ return this; }
208
virtual Operand* merge1(Operand* other);
209
virtual void printToString(TR::StringBuf *buf);
210
virtual KnowledgeLevel getKnowledgeLevel() { return MUTABLE_CALLSITE_TARGET; }
211
TR::KnownObjectTable::Index getMethodHandleIndex(){ return methodHandleIndex; }
212
TR::KnownObjectTable::Index getMutableCallsiteIndex() { return mutableCallsiteIndex; }
213
TR::KnownObjectTable::Index mutableCallsiteIndex;
214
TR::KnownObjectTable::Index methodHandleIndex;
215
};
216
217
class InterpreterEmulator : public TR_ByteCodeIteratorWithState<TR_J9ByteCode, J9BCunknown, TR_J9ByteCodeIterator, Operand *>
218
{
219
typedef TR_ByteCodeIteratorWithState<TR_J9ByteCode, J9BCunknown, TR_J9ByteCodeIterator, Operand *> Base;
220
221
public:
222
InterpreterEmulator(
223
TR_CallTarget *calltarget,
224
TR::ResolvedMethodSymbol * methodSymbol,
225
TR_J9VMBase * fe,
226
TR::Compilation * comp,
227
TR_LogTracer *tracer,
228
TR_EstimateCodeSize *ecs)
229
: Base(methodSymbol, comp),
230
_calltarget(calltarget),
231
_tracer(tracer),
232
_ecs(ecs),
233
_iteratorWithState(false)
234
{
235
TR_J9ByteCodeIterator::initialize(static_cast<TR_ResolvedJ9Method *>(methodSymbol->getResolvedMethod()), fe);
236
_flags = NULL;
237
_stacks = NULL;
238
_currentLocalObjectInfo = NULL;
239
_localObjectInfos = NULL;
240
_currentCallSite = NULL;
241
_currentCallMethod = NULL;
242
_currentCallMethodUnrefined = NULL;
243
_numSlots = 0;
244
_callerIsThunkArchetype = _calltarget->_calleeMethod->convertToMethod()->isArchetypeSpecimen();
245
246
_operandBuf = NULL;
247
if (_tracer->heuristicLevel() || _tracer->debugLevel())
248
{
249
TR::Region &stackRegion = comp->trMemory()->currentStackRegion();
250
_operandBuf = new (stackRegion) TR::StringBuf(stackRegion);
251
}
252
}
253
TR_LogTracer *tracer() { return _tracer; }
254
/* \brief Initialize data needed for looking for callsites
255
*
256
* \param blocks
257
* blocks generated from bytecodes
258
*
259
* \param flags
260
* flags with bits to indicate property of each bytecode. The flags are set by \ref TR_J9EstimateCodeSize::processBytecodeAndGenerateCFG.
261
*
262
* \param callSites
263
* the call sites array to be filled in with callsites found
264
*
265
* \param cfg
266
* CFG generated \ref TR_J9EstimateCodeSize::processBytecodeAndGenerateCFG from bytecodes
267
*
268
* \param recursionDepth
269
* the depth of inlining layers
270
*
271
* \parm callstack
272
* the call stack from the current inlined call target to the method being compiled
273
*/
274
void prepareToFindAndCreateCallsites(TR::Block **blocks, flags8_t * flags, TR_CallSite ** callSites, TR::CFG* cfg, TR_ByteCodeInfo *newBCInfo, int32_t recursionDepth, TR_CallStack *callstack);
275
276
/*
277
* \brief look for calls in bytecodes and create callsites
278
*
279
* \param wasPeekingSuccessfull
280
* indicate whether trees has been generated by peeking ilgen
281
*
282
* \param withState
283
* whether the bytecode iteration should be with or without state
284
*
285
* \return whether callsites are created successfully. Return false if failed for reasons like unexpected bytecodes etc.
286
*/
287
bool findAndCreateCallsitesFromBytecodes(bool wasPeekingSuccessfull, bool withState);
288
void setBlocks(TR::Block **blocks) { _blocks = blocks; }
289
TR_StackMemory trStackMemory() { return _trMemory; }
290
291
/*
292
* \brief Compute prex arg info for the given call site
293
*/
294
TR_PrexArgInfo* computePrexInfo(
295
TR_CallSite *callsite, TR::KnownObjectTable::Index appendix);
296
TR_PrexArgument* createPrexArgFromOperand(Operand* operand);
297
Operand* createOperandFromPrexArg(TR_PrexArgument* arg);
298
299
bool _nonColdCallExists;
300
bool _inlineableCallExists;
301
302
enum BytecodePropertyFlag
303
{
304
bbStart = 0x01, // whether the current bytecode is at bbstart
305
isCold = 0x02, // whther the bytecode is on a cold path
306
isBranch = 0x04, // whther the bytecode is a branch
307
isUnsanitizeable = 0x08,
308
};
309
310
private:
311
// the following methods can only be called when the iterator has state
312
313
/*
314
* Initialize the data structures needed for iterator with state
315
*/
316
void initializeIteratorWithState();
317
/*
318
* push and pop operands on stack according to given bytecode
319
*
320
* \return false if some error occurred such as unexpected bytecodes.
321
*/
322
bool maintainStack(TR_J9ByteCode bc);
323
void maintainStackForIf(TR_J9ByteCode bc);
324
void maintainStackForGetField();
325
void maintainStackForAload(int slotIndex);
326
void maintainStackForReturn();
327
/*
328
* \brief helper to pop arguments from the stack and push the result for calls
329
*
330
* \param numArgs
331
* Number of arguments of the call
332
*
333
* \param result
334
* the operand reprenting the call return value
335
*
336
* \param returnType
337
* Return type of the call
338
*/
339
void maintainStackForCall(Operand *result, int32_t numArgs, TR::DataType returnType);
340
/*
341
* \brief helper to pop arguments from the stack and push the result for calls
342
*/
343
void maintainStackForCall();
344
/*
345
* \brief refine invokestatic callee method based on operands when possible
346
*/
347
void refineResolvedCalleeForInvokestatic(TR_ResolvedMethod *&callee, TR::KnownObjectTable::Index & mcsIndex, TR::KnownObjectTable::Index & mhIndex, bool & isIndirectCall);
348
/*
349
* \brief refine invokevirtual callee method based on operands when possible
350
*/
351
void refineResolvedCalleeForInvokevirtual(TR_ResolvedMethod*& callee, bool &isIndirectCall);
352
/*
353
* \brief Compute result of the given call based on operand stack state
354
*/
355
Operand *getReturnValue(TR_ResolvedMethod *callee);
356
void dumpStack();
357
void pushUnknownOperand() { Base::push(_unknownOperand); }
358
// doesn't need to handle execeptions yet as they don't exist in method handle thunk archetypes
359
virtual void findAndMarkExceptionRanges(){ }
360
/*
361
* \brief Propagte state state and local variable state to next target
362
*/
363
virtual void saveStack(int32_t targetIndex);
364
365
// the following methods can be used in both stateless and with state mode
366
367
/*
368
* \brief look for and set the next bytecode index to visit
369
*
370
* \return the bytecode value to visit
371
*/
372
TR_J9ByteCode findNextByteCodeToVisit();
373
374
/*
375
* \brief tell whether the given bcIndex has been generated.
376
*
377
* \note This query is used to avoid regenerating bytecodes which shouldn't happen at stateless mode
378
*/
379
bool isGenerated(int32_t bcIndex) { return _iteratorWithState ? Base::isGenerated(bcIndex): false; }
380
/*
381
* \brief Set up operand stack and local slot array for block starting at given bytecode index
382
*
383
* \param index
384
* Bytecode index at the block entry
385
*/
386
virtual int32_t setupBBStartContext(int32_t index);
387
/*
388
* \brief set up object info in local slots at entry of a block
389
*
390
* \param index
391
* Bytecode index at the block entry
392
*/
393
void setupBBStartLocalObjectState(int32_t index);
394
/*
395
* \brief set up object info in local slots for the method entry
396
*/
397
void setupMethodEntryLocalObjectState();
398
/*
399
* \brief set up operand stack state at entry of a block
400
*
401
* \param index
402
* Bytecode index at the block entry
403
*/
404
void setupBBStartStackState(int32_t index);
405
406
void visitInvokedynamic();
407
void visitInvokevirtual();
408
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
409
void visitInvokehandle();
410
void updateKnotAndCreateCallSiteUsingInvokeCacheArray(TR_ResolvedJ9Method* owningMethod, uintptr_t * invokeCacheArray, int32_t cpIndex);
411
#endif
412
void visitInvokespecial();
413
void visitInvokestatic();
414
void visitInvokeinterface();
415
void findTargetAndUpdateInfoForCallsite(
416
TR_CallSite *callsite,
417
TR::KnownObjectTable::Index appendix = TR::KnownObjectTable::UNKNOWN);
418
bool isCurrentCallUnresolvedOrCold(TR_ResolvedMethod *resolvedMethod, bool isUnresolvedInCP);
419
void debugUnresolvedOrCold(TR_ResolvedMethod *resolvedMethod);
420
void maintainStackForAstore(int slotIndex);
421
void maintainStackForldc(int32_t cpIndex);
422
void maintainStackForGetStatic();
423
/*
424
* \brief Check if a block has predecessors whose bytecodes haven't been visited
425
*/
426
bool hasUnvisitedPred(TR::Block* block);
427
428
typedef TR_Array<Operand*> OperandArray;
429
void printOperandArray(OperandArray* operands);
430
/*
431
* \brief Merge second operand into the first, does an intersect operand on every operand in the array
432
*/
433
void mergeOperandArray(OperandArray *first, OperandArray *second);
434
435
436
TR_LogTracer *_tracer;
437
TR_EstimateCodeSize *_ecs;
438
Operand * _unknownOperand; // used whenever the iterator can't reason about an operand
439
TR_CallTarget *_calltarget; // the target method to inline
440
bool _iteratorWithState;
441
flags8_t * _InterpreterEmulatorFlags; // flags with bits to indicate property of each bytecode.
442
TR_CallSite ** _callSites;
443
TR_CallSite * _currentCallSite; // Store created callsite if visiting invoke* bytecodes
444
TR_ResolvedMethod * _currentCallMethod; // Resolved method for invoke* bytecodes, some calls won't have call site created due to coldness info
445
TR_ResolvedMethod * _currentCallMethodUnrefined; // Call method without any refinement applied to it
446
TR::CFG* _cfg;
447
TR_ByteCodeInfo *_newBCInfo;
448
int32_t _recursionDepth;
449
TR_CallStack *_callStack; // the call stack from the current inlined call target to the method being compiled
450
bool _wasPeekingSuccessfull;
451
TR::Block *_currentInlinedBlock;
452
TR_prevArgs _pca;
453
454
bool _callerIsThunkArchetype;
455
// State of local object for current bytecode being visited
456
OperandArray* _currentLocalObjectInfo;
457
// Array of local object info arrays, indexed by bytecode index
458
OperandArray** _localObjectInfos;
459
// Number of local slots
460
int32_t _numSlots;
461
462
TR::StringBuf *_operandBuf; // for debug printing
463
};
464
#endif
465
466