Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/optimizer/InterpreterEmulator.cpp
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
#include "optimizer/InterpreterEmulator.hpp"
23
#include "optimizer/J9EstimateCodeSize.hpp"
24
#include "env/VMAccessCriticalSection.hpp"
25
#include "env/JSR292Methods.h"
26
#include "optimizer/PreExistence.hpp"
27
#include "optimizer/J9CallGraph.hpp"
28
#include "ilgen/IlGenRequest.hpp"
29
#include "jilconsts.h"
30
#include "il/ParameterSymbol.hpp"
31
#include "optimizer/PreExistence.hpp"
32
#include "optimizer/TransformUtil.hpp"
33
#include "il/Node_inlines.hpp"
34
#if defined(J9VM_OPT_JITSERVER)
35
#include "control/CompilationRuntime.hpp"
36
#include "env/j9methodServer.hpp"
37
#endif /* defined(J9VM_OPT_JITSERVER) */
38
39
const char* Operand::KnowledgeStrings[] = {"NONE", "OBJECT", "MUTABLE_CALLSITE_TARGET", "PREEXISTENT", "FIXED_CLASS", "KNOWN_OBJECT", "ICONST" };
40
41
char*
42
ObjectOperand::getSignature(TR::Compilation *comp, TR_Memory *trMemory)
43
{
44
if (!_signature && _clazz)
45
_signature = TR::Compiler->cls.classSignature(comp, _clazz, trMemory);
46
return _signature;
47
}
48
49
KnownObjOperand::KnownObjOperand(TR::KnownObjectTable::Index koi, TR_OpaqueClassBlock* clazz)
50
: knownObjIndex(koi), FixedClassOperand(clazz)
51
{
52
TR_ASSERT_FATAL(knownObjIndex != TR::KnownObjectTable::UNKNOWN, "Unexpected unknown object");
53
}
54
55
TR_OpaqueClassBlock*
56
KnownObjOperand::getClass()
57
{
58
if (_clazz)
59
return _clazz;
60
61
TR::Compilation* comp = TR::comp();
62
auto knot = comp->getOrCreateKnownObjectTable();
63
if (!knot || knot->isNull(knownObjIndex))
64
return NULL;
65
66
_clazz = comp->fej9()->getObjectClassFromKnownObjectIndex(comp, knownObjIndex);
67
68
return _clazz;
69
}
70
71
ObjectOperand*
72
KnownObjOperand::asObjectOperand()
73
{
74
if (getClass())
75
return this;
76
77
return NULL;
78
}
79
80
// FixedClassOperand need the class, if we can't get the class, return NULL
81
FixedClassOperand*
82
KnownObjOperand::asFixedClassOperand()
83
{
84
if (getClass())
85
return this;
86
87
return NULL;
88
}
89
90
Operand*
91
Operand::merge(Operand* other)
92
{
93
if (getKnowledgeLevel() > other->getKnowledgeLevel())
94
return other->merge1(this);
95
else
96
return merge1(other);
97
}
98
99
Operand*
100
Operand::merge1(Operand* other)
101
{
102
if (this == other)
103
return this;
104
else
105
return NULL;
106
}
107
108
Operand*
109
IconstOperand::merge1(Operand* other)
110
{
111
TR_ASSERT(other->getKnowledgeLevel() >= this->getKnowledgeLevel(), "Should be calling other->merge1(this)");
112
IconstOperand* otherIconst = other->asIconst();
113
if (otherIconst && this->intValue == otherIconst->intValue)
114
return this;
115
else
116
return NULL;
117
}
118
119
// TODO: check instanceOf relationship and create new Operand if neccessary
120
Operand*
121
ObjectOperand::merge1(Operand* other)
122
{
123
TR_ASSERT(other->getKnowledgeLevel() >= this->getKnowledgeLevel(), "Should be calling other->merge1(this)");
124
ObjectOperand* otherObject = other->asObjectOperand();
125
if (otherObject && this->_clazz == otherObject->_clazz)
126
return this;
127
else
128
return NULL;
129
}
130
131
// Both are preexistent objects
132
Operand*
133
PreexistentObjectOperand::merge1(Operand* other)
134
{
135
TR_ASSERT(other->getKnowledgeLevel() >= this->getKnowledgeLevel(), "Should be calling other->merge1(this)");
136
PreexistentObjectOperand* otherPreexistentObjectOperand = other->asPreexistentObjectOperand();
137
if (otherPreexistentObjectOperand && this->_clazz == otherPreexistentObjectOperand->_clazz)
138
return this;
139
else
140
return NULL;
141
}
142
143
Operand*
144
FixedClassOperand::merge1(Operand* other)
145
{
146
TR_ASSERT(other->getKnowledgeLevel() >= this->getKnowledgeLevel(), "Should be calling other->merge1(this)");
147
FixedClassOperand* otherFixedClass = other->asFixedClassOperand();
148
if (otherFixedClass && this->_clazz == otherFixedClass->_clazz)
149
return this;
150
else
151
return NULL;
152
}
153
154
Operand*
155
KnownObjOperand::merge1(Operand* other)
156
{
157
TR_ASSERT(other->getKnowledgeLevel() >= this->getKnowledgeLevel(), "Should be calling other->merge1(this)");
158
KnownObjOperand* otherKnownObj = other->asKnownObject();
159
if (otherKnownObj && this->knownObjIndex == otherKnownObj->knownObjIndex)
160
return this;
161
else
162
return NULL;
163
}
164
165
Operand*
166
MutableCallsiteTargetOperand::merge1(Operand* other)
167
{
168
TR_ASSERT(other->getKnowledgeLevel() >= this->getKnowledgeLevel(), "Should be calling other->merge1(this)");
169
MutableCallsiteTargetOperand* otherMutableCallsiteTarget = other->asMutableCallsiteTargetOperand();
170
if (otherMutableCallsiteTarget &&
171
this->mutableCallsiteIndex== otherMutableCallsiteTarget->mutableCallsiteIndex &&
172
this->methodHandleIndex == otherMutableCallsiteTarget->methodHandleIndex)
173
return this;
174
else
175
return NULL;
176
}
177
178
void
179
Operand::printToString(TR::StringBuf *buf)
180
{
181
buf->appendf("(unknown)");
182
}
183
184
void
185
IconstOperand::printToString(TR::StringBuf *buf)
186
{
187
buf->appendf("(iconst=%d)", intValue);
188
}
189
190
void
191
ObjectOperand::printToString(TR::StringBuf *buf)
192
{
193
buf->appendf("(%s=clazz%p)", KnowledgeStrings[getKnowledgeLevel()], getClass());
194
}
195
196
void
197
KnownObjOperand::printToString(TR::StringBuf *buf)
198
{
199
buf->appendf("(obj%d)", getKnownObjectIndex());
200
}
201
202
void
203
MutableCallsiteTargetOperand::printToString(TR::StringBuf *buf)
204
{
205
buf->appendf("(mh=%d, mcs=%d)", getMethodHandleIndex(), getMutableCallsiteIndex());
206
}
207
208
void
209
InterpreterEmulator::printOperandArray(OperandArray* operands)
210
{
211
int32_t size = operands->size();
212
for (int32_t i = 0; i < size; i++)
213
{
214
_operandBuf->clear();
215
(*operands)[i]->printToString(_operandBuf);
216
traceMsg(comp(), "[%d]=%s, ", i, _operandBuf->text());
217
}
218
if (size > 0)
219
traceMsg(comp(), "\n");
220
}
221
222
// Merge second OperandArray into the first one
223
// The merge does a union
224
//
225
void InterpreterEmulator::mergeOperandArray(OperandArray *first, OperandArray *second)
226
{
227
bool enableTrace = tracer()->debugLevel();
228
if (enableTrace)
229
{
230
traceMsg(comp(), "Operands before merging:\n");
231
printOperandArray(first);
232
}
233
234
bool changed = false;
235
for (int i = 0; i < _numSlots; i++)
236
{
237
Operand* firstObj = (*first)[i];
238
Operand* secondObj = (*second)[i];
239
240
firstObj = firstObj->merge(secondObj);
241
if (firstObj == NULL)
242
firstObj = _unknownOperand;
243
244
if (firstObj != (*first)[i])
245
changed = true;
246
}
247
248
if (enableTrace)
249
{
250
if (changed)
251
{
252
traceMsg(comp(), "Operands after merging:\n");
253
printOperandArray(first);
254
}
255
else
256
traceMsg(comp(), "Operands is not changed after merging\n");
257
}
258
}
259
260
void
261
InterpreterEmulator::maintainStackForIf(TR_J9ByteCode bc)
262
{
263
TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");
264
TR_ASSERT_FATAL(bc == J9BCificmpeq || bc == J9BCificmpne, "InterpreterEmulator::maintainStackForIf can only be called with J9BCificmpeq and J9BCificmpne\n");
265
int32_t branchBC = _bcIndex + next2BytesSigned();
266
int32_t fallThruBC = _bcIndex + 3;
267
IconstOperand * second = pop()->asIconst();
268
IconstOperand * first = pop()->asIconst();
269
bool canBranch = true;
270
bool canFallThru = true;
271
// Comment out the branch folding as all the paths have to be interpreted in order
272
// to propagate object info in operand stack or local slots. Since branch folding
273
// currently only affects thunk archetypes, with similar branch folding in ilgen,
274
// calls in dead path won't be inlined, disabling the following code doesn't affect
275
// performance
276
// TODO: add code to record dead path and ignore it in object info propagation, enable
277
// the following code if branch folding is possible in LambdaForm methods
278
//
279
if (false && second && first)
280
{
281
switch (bc)
282
{
283
case J9BCificmpeq:
284
canBranch = second->intValue == first->intValue;
285
debugTrace(tracer(), "maintainStackForIf ifcmpeq %d == %d\n", second->intValue, first->intValue);
286
break;
287
case J9BCificmpne:
288
canBranch = second->intValue != first->intValue;
289
debugTrace(tracer(), "maintainStackForIf ifcmpne %d != %d\n", second->intValue, first->intValue);
290
break;
291
292
default:
293
break;
294
}
295
canFallThru = !canBranch;
296
}
297
298
// The branch target can be successor of the fall through, so gen fall through block first such
299
// that the predecessor is interpreted before the successor in order to propagate the operand
300
// stack and local slots state.
301
// This doesn't work when the fall through contain control flow, but there is no functional issue
302
// as the object info won't be propagated if there exists unvisited predecessor. This will be
303
// fixed when we traverse the bytecodes in reverse post order at CFG level.
304
//
305
if (canFallThru)
306
{
307
debugTrace(tracer(), "maintainStackForIf canFallThrough to bcIndex=%d\n", fallThruBC);
308
genTarget(fallThruBC);
309
}
310
311
if (canBranch)
312
{
313
debugTrace(tracer(), "maintainStackForIf canBranch to bcIndex=%d\n", branchBC);
314
genTarget(branchBC);
315
}
316
317
}
318
319
void
320
InterpreterEmulator::maintainStackForGetField()
321
{
322
TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");
323
TR::DataType type = TR::NoType;
324
uint32_t fieldOffset;
325
int32_t cpIndex = next2Bytes();
326
Operand *newOperand = _unknownOperand;
327
TR::Symbol *fieldSymbol = TR::Symbol::createPossiblyRecognizedShadowFromCP(
328
comp(), trStackMemory(), _calltarget->_calleeMethod, cpIndex, &type, &fieldOffset, false);
329
330
TR::KnownObjectTable *knot = comp()->getKnownObjectTable();
331
if (knot &&
332
top()->asKnownObject() &&
333
!knot->isNull(top()->getKnownObjectIndex())
334
&& type == TR::Address)
335
{
336
if (fieldSymbol == NULL)
337
{
338
debugTrace(tracer(), "field is unresolved");
339
}
340
else if (!comp()->fej9()->canDereferenceAtCompileTimeWithFieldSymbol(fieldSymbol, cpIndex, _calltarget->_calleeMethod))
341
{
342
debugTrace(tracer(), "field is not foldable");
343
}
344
else
345
{
346
TR::KnownObjectTable::Index baseObjectIndex = top()->getKnownObjectIndex();
347
TR::KnownObjectTable::Index resultIndex = TR::KnownObjectTable::UNKNOWN;
348
uintptr_t baseObjectAddress = 0;
349
uintptr_t fieldAddress = 0;
350
bool avoidFolding = true;
351
352
#if defined(J9VM_OPT_JITSERVER)
353
if (comp()->isOutOfProcessCompilation())
354
{
355
TR_ResolvedJ9JITServerMethod *serverMethod = static_cast<TR_ResolvedJ9JITServerMethod*>(_calltarget->_calleeMethod);
356
TR_ResolvedMethod *clientMethod = serverMethod->getRemoteMirror();
357
358
auto stream = TR::CompilationInfo::getStream();
359
stream->write(JITServer::MessageType::KnownObjectTable_dereferenceKnownObjectField,
360
baseObjectIndex, clientMethod, cpIndex);
361
362
auto recv = stream->read<TR::KnownObjectTable::Index, uintptr_t*, uintptr_t, uintptr_t, bool>();
363
resultIndex = std::get<0>(recv);
364
uintptr_t *objectPointerReference = std::get<1>(recv);
365
fieldAddress = std::get<2>(recv);
366
baseObjectAddress = std::get<3>(recv);
367
avoidFolding = std::get<4>(recv);
368
369
if (resultIndex != TR::KnownObjectTable::UNKNOWN)
370
knot->updateKnownObjectTableAtServer(resultIndex, objectPointerReference);
371
}
372
else
373
#endif /* defined(J9VM_OPT_JITSERVER) */
374
{
375
TR::VMAccessCriticalSection dereferenceKnownObjectField(comp()->fej9());
376
baseObjectAddress = knot->getPointer(baseObjectIndex);
377
TR_OpaqueClassBlock *baseObjectClass = comp()->fej9()->getObjectClass(baseObjectAddress);
378
TR_OpaqueClassBlock *fieldDeclaringClass = _calltarget->_calleeMethod->getDeclaringClassFromFieldOrStatic(comp(), cpIndex);
379
380
avoidFolding = TR::TransformUtil::avoidFoldingInstanceField(
381
baseObjectAddress, fieldSymbol, fieldOffset, cpIndex, _calltarget->_calleeMethod, comp());
382
383
if (fieldDeclaringClass && comp()->fej9()->isInstanceOf(baseObjectClass, fieldDeclaringClass, true) == TR_yes)
384
{
385
fieldAddress = comp()->fej9()->getReferenceFieldAtAddress(baseObjectAddress + fieldOffset);
386
resultIndex = knot->getOrCreateIndex(fieldAddress);
387
}
388
}
389
390
bool fail = resultIndex == TR::KnownObjectTable::UNKNOWN;
391
if (fail || avoidFolding)
392
{
393
int32_t len = 0;
394
debugTrace(
395
tracer(),
396
"%s field in obj%d: %s",
397
fail ? "failed to determine value of" : "avoid folding sometimes-foldable",
398
baseObjectIndex,
399
_calltarget->_calleeMethod->fieldName(cpIndex, len, this->trMemory()));
400
}
401
else
402
{
403
// It's OK to print fieldAddress and baseObjectAddress here even
404
// without VM access. There's no meaningful difference between:
405
// - printing the object's address, then allowing it to move; and
406
// - observing the objects's address, then allowing it to move,
407
// then finally printing the observed address.
408
newOperand = new (trStackMemory()) KnownObjOperand(resultIndex);
409
int32_t len = 0;
410
debugTrace(tracer(), "dereference obj%d (%p)from field %s(offset = %d) of base obj%d(%p)\n",
411
newOperand->getKnownObjectIndex(), (void *)fieldAddress, _calltarget->_calleeMethod->fieldName(cpIndex, len, this->trMemory()),
412
fieldOffset, baseObjectIndex, baseObjectAddress);
413
}
414
}
415
}
416
pop();
417
push(newOperand);
418
}
419
420
void
421
InterpreterEmulator::saveStack(int32_t targetIndex)
422
{
423
if (!_iteratorWithState)
424
return;
425
426
// Propagate stack state to successor
427
if (!_stack->isEmpty())
428
{
429
if (!_stacks[targetIndex])
430
_stacks[targetIndex] = new (trStackMemory()) ByteCodeStack(*_stack);
431
else
432
{
433
TR_ASSERT_FATAL(_stacks[targetIndex]->size() == _stack->size(), "operand stack from two paths must have the same size, predecessor bci %d target bci %d\n", _bcIndex, targetIndex);
434
mergeOperandArray(_stacks[targetIndex], _stack);
435
}
436
}
437
438
// Propagate local object info to successor
439
if (_numSlots)
440
{
441
if (!_localObjectInfos[targetIndex])
442
_localObjectInfos[targetIndex] = new (trStackMemory()) OperandArray(*_currentLocalObjectInfo);
443
else
444
mergeOperandArray(_localObjectInfos[targetIndex], _currentLocalObjectInfo);
445
}
446
}
447
448
void
449
InterpreterEmulator::initializeIteratorWithState()
450
{
451
_iteratorWithState = true;
452
_unknownOperand = new (trStackMemory()) Operand();
453
uint32_t size = this->maxByteCodeIndex() + 5;
454
_flags = (flags8_t *) this->trMemory()->allocateStackMemory(size * sizeof(flags8_t));
455
_stacks = (ByteCodeStack * *) this->trMemory()->allocateStackMemory(size * sizeof(ByteCodeStack *));
456
memset(_flags, 0, size * sizeof(flags8_t));
457
memset(_stacks, 0, size * sizeof(ByteCodeStack *));
458
_stack = new (trStackMemory()) TR_Stack<Operand *>(this->trMemory(), 20, false, stackAlloc);
459
_localObjectInfos = (OperandArray**) this->trMemory()->allocateStackMemory(size * sizeof(OperandArray *));
460
memset(_localObjectInfos, 0, size * sizeof(OperandArray *));
461
462
int32_t numParmSlots = method()->numberOfParameterSlots();
463
_numSlots = numParmSlots + method()->numberOfTemps();
464
465
genBBStart(0);
466
setupBBStartContext(0);
467
this->setIndex(0);
468
}
469
470
void
471
InterpreterEmulator::setupMethodEntryLocalObjectState()
472
{
473
TR_PrexArgInfo *argInfo = _calltarget->_ecsPrexArgInfo;
474
if (argInfo)
475
{
476
TR_ASSERT_FATAL(argInfo->getNumArgs() == method()->numberOfParameters(), "Prex arg number should match parm number");
477
478
if(tracer()->heuristicLevel())
479
{
480
heuristicTrace(tracer(), "Save argInfo to slot state array");
481
argInfo->dumpTrace();
482
}
483
484
method()->makeParameterList(_methodSymbol);
485
ListIterator<TR::ParameterSymbol> parms(&_methodSymbol->getParameterList());
486
487
// save prex arg into local var arrays
488
for (TR::ParameterSymbol *p = parms.getFirst(); p != NULL; p = parms.getNext())
489
{
490
int32_t ordinal = p->getOrdinal();
491
int32_t slotIndex = p->getSlot();
492
TR_PrexArgument *prexArgument = argInfo->get(ordinal);
493
if (!prexArgument)
494
{
495
(*_currentLocalObjectInfo)[slotIndex] = _unknownOperand;
496
}
497
else
498
{
499
auto operand = createOperandFromPrexArg(prexArgument);
500
if (operand)
501
{
502
(*_currentLocalObjectInfo)[slotIndex] = operand;
503
}
504
else
505
(*_currentLocalObjectInfo)[slotIndex] = _unknownOperand;
506
}
507
if (tracer()->heuristicLevel())
508
{
509
_operandBuf->clear();
510
(*_currentLocalObjectInfo)[slotIndex]->printToString(_operandBuf);
511
heuristicTrace(
512
tracer(),
513
"Creating operand %s for parm %d slot %d from PrexArgument %p",
514
_operandBuf->text(),
515
ordinal,
516
slotIndex,
517
prexArgument);
518
}
519
}
520
}
521
}
522
523
bool
524
InterpreterEmulator::hasUnvisitedPred(TR::Block* block)
525
{
526
TR_PredecessorIterator pi(block);
527
for (TR::CFGEdge *edge = pi.getFirst(); edge != NULL; edge = pi.getNext())
528
{
529
TR::Block *fromBlock = toBlock(edge->getFrom());
530
auto fromBCIndex = fromBlock->getEntry()->getNode()->getByteCodeIndex();
531
if (!isGenerated(fromBCIndex))
532
{
533
return true;
534
}
535
}
536
537
return false;
538
}
539
540
void
541
InterpreterEmulator::setupBBStartStackState(int32_t index)
542
{
543
if (index == 0)
544
return;
545
546
auto block = blocks(index);
547
auto stack = _stacks[index];
548
if (stack && hasUnvisitedPred(block))
549
{
550
heuristicTrace(tracer(), "block_%d at bc index %d has unvisited predecessor, setting stack operand info to unknown", block->getNumber(), index);
551
for (int32_t i = 0; i < stack->size(); ++i)
552
(*stack)[i] = _unknownOperand;
553
}
554
}
555
556
void
557
InterpreterEmulator::setupBBStartLocalObjectState(int32_t index)
558
{
559
if (_numSlots == 0)
560
return;
561
562
if (!_localObjectInfos[index])
563
{
564
_localObjectInfos[index] = new (trStackMemory()) OperandArray(trMemory(), _numSlots, false, stackAlloc);
565
for (int32_t i = 0; i < _numSlots; i++)
566
(*_localObjectInfos[index])[i] = _unknownOperand;
567
}
568
else if (hasUnvisitedPred(blocks(index)))
569
{
570
heuristicTrace(tracer(), "block_%d at bc index %d has unvisited predecessor, setting local object info to unknown", blocks(index)->getNumber(), index);
571
for (int32_t i = 0; i < _numSlots; i++)
572
(*_localObjectInfos[index])[i] = _unknownOperand;
573
}
574
575
_currentLocalObjectInfo = _localObjectInfos[index];
576
577
if (index == 0)
578
setupMethodEntryLocalObjectState();
579
}
580
581
int32_t
582
InterpreterEmulator::setupBBStartContext(int32_t index)
583
{
584
if (_iteratorWithState)
585
{
586
setupBBStartStackState(index);
587
setupBBStartLocalObjectState(index);
588
}
589
Base::setupBBStartContext(index);
590
return index;
591
}
592
593
bool
594
InterpreterEmulator::maintainStack(TR_J9ByteCode bc)
595
{
596
TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");
597
int slotIndex = -1;
598
switch (bc)
599
{
600
case J9BCgetfield: maintainStackForGetField(); break;
601
case J9BCaload0: slotIndex = 0; maintainStackForAload(slotIndex); break;
602
case J9BCaload1: slotIndex = 1; maintainStackForAload(slotIndex); break;
603
case J9BCaload2: slotIndex = 2; maintainStackForAload(slotIndex); break;
604
case J9BCaload3: slotIndex = 3; maintainStackForAload(slotIndex); break;
605
case J9BCaload: slotIndex = nextByte(); maintainStackForAload(slotIndex); break;
606
case J9BCaloadw: slotIndex = next2Bytes(); maintainStackForAload(slotIndex); break;
607
608
case J9BCinvokespecial:
609
case J9BCinvokespecialsplit:
610
case J9BCinvokevirtual:
611
case J9BCinvokestatic:
612
case J9BCinvokestaticsplit:
613
case J9BCinvokedynamic:
614
case J9BCinvokehandle:
615
maintainStackForCall();
616
break;
617
case J9BCiconstm1: push (new (trStackMemory()) IconstOperand(-1)); break;
618
case J9BCiconst0: push (new (trStackMemory()) IconstOperand(0)); break;
619
case J9BCiconst1: push (new (trStackMemory()) IconstOperand(1)); break;
620
case J9BCiconst2: push (new (trStackMemory()) IconstOperand(2)); break;
621
case J9BCiconst3: push (new (trStackMemory()) IconstOperand(3)); break;
622
case J9BCiconst4: push (new (trStackMemory()) IconstOperand(4)); break;
623
case J9BCiconst5: push (new (trStackMemory()) IconstOperand(5)); break;
624
case J9BCifne:
625
push (new (trStackMemory()) IconstOperand(0));
626
maintainStackForIf(J9BCificmpne);
627
break;
628
case J9BCifeq:
629
push (new (trStackMemory()) IconstOperand(0));
630
maintainStackForIf(J9BCificmpeq);
631
break;
632
case J9BCgoto:
633
genTarget(bcIndex() + next2BytesSigned());
634
break;
635
case J9BCpop:
636
case J9BCputfield:
637
case J9BCputstatic:
638
pop();
639
break;
640
case J9BCladd:
641
case J9BCiadd:
642
case J9BCisub:
643
case J9BCiand:
644
popn(2);
645
pushUnknownOperand();
646
break;
647
case J9BCistore: case J9BClstore: case J9BCfstore: case J9BCdstore:
648
case J9BCistorew: case J9BClstorew: case J9BCfstorew: case J9BCdstorew:
649
case J9BCistore0: case J9BCistore1: case J9BCistore2: case J9BCistore3:
650
case J9BClstore0: case J9BClstore1: case J9BClstore2: case J9BClstore3:
651
case J9BCfstore0: case J9BCfstore1: case J9BCfstore2: case J9BCfstore3:
652
case J9BCdstore0: case J9BCdstore1: case J9BCdstore2: case J9BCdstore3:
653
pop();
654
break;
655
// Maintain stack for object store
656
case J9BCastorew: maintainStackForAstore(next2Bytes()); break;
657
case J9BCastore: maintainStackForAstore(nextByte()); break;
658
case J9BCastore0: maintainStackForAstore(0); break;
659
case J9BCastore1: maintainStackForAstore(1); break;
660
case J9BCastore2: maintainStackForAstore(2); break;
661
case J9BCastore3: maintainStackForAstore(3); break;
662
663
case J9BCiload0: case J9BCiload1: case J9BCiload2: case J9BCiload3:
664
case J9BCdload0: case J9BCdload1: case J9BCdload2: case J9BCdload3:
665
case J9BClload0: case J9BClload1: case J9BClload2: case J9BClload3:
666
case J9BCfload0: case J9BCfload1: case J9BCfload2: case J9BCfload3:
667
case J9BCiloadw: case J9BClloadw: case J9BCfloadw: case J9BCdloadw:
668
case J9BCiload: case J9BClload: case J9BCfload: case J9BCdload:
669
pushUnknownOperand();
670
break;
671
case J9BCgetstatic:
672
maintainStackForGetStatic();
673
break;
674
case J9BCgenericReturn:
675
case J9BCReturnC:
676
case J9BCReturnS:
677
case J9BCReturnB:
678
case J9BCReturnZ:
679
maintainStackForReturn();
680
break;
681
case J9BCi2l:
682
break;
683
case J9BCcheckcast:
684
break;
685
case J9BCdup:
686
push(top());
687
break;
688
case J9BCldc:
689
maintainStackForldc(nextByte()); break;
690
default:
691
static const bool assertfatal = feGetEnv("TR_AssertFatalForUnexpectedBytecodeInMethodHandleThunk") ? true: false;
692
if (!assertfatal)
693
debugTrace(tracer(), "unexpected bytecode in thunk archetype %s (%p) at bcIndex %d %s (%d)\n", _calltarget->_calleeMethod->signature(comp()->trMemory()), _calltarget, bcIndex(), comp()->fej9()->getByteCodeName(nextByte(0)), bc);
694
else
695
TR_ASSERT_FATAL(0, "unexpected bytecode in thunk archetype %s (%p) at bcIndex %d %s (%d)\n", _calltarget->_calleeMethod->signature(comp()->trMemory()), _calltarget, bcIndex(), comp()->fej9()->getByteCodeName(nextByte(0)), bc);
696
697
TR::DebugCounter::incStaticDebugCounter(comp(),
698
TR::DebugCounter::debugCounterName(comp(),
699
"InterpreterEmulator.unexpectedBytecode/(root=%s)/(%s)/bc=%d/%s",
700
comp()->signature(),
701
_calltarget->_calleeMethod->signature(comp()->trMemory()),
702
_bcIndex,
703
comp()->fej9()->getByteCodeName(nextByte(0)))
704
);
705
return false;
706
}
707
return true;
708
}
709
710
void
711
InterpreterEmulator::maintainStackForReturn()
712
{
713
if (method()->returnType() != TR::NoType)
714
pop();
715
}
716
717
void
718
InterpreterEmulator::maintainStackForGetStatic()
719
{
720
TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");
721
if (comp()->compileRelocatableCode())
722
{
723
pushUnknownOperand();
724
return;
725
}
726
727
int32_t cpIndex = next2Bytes();
728
debugTrace(tracer(), "getstatic cpIndex %d", cpIndex);
729
730
void * dataAddress;
731
bool isVolatile, isPrivate, isUnresolvedInCP, isFinal;
732
TR::DataType type = TR::NoType;
733
auto owningMethod = _calltarget->_calleeMethod;
734
bool resolved = owningMethod->staticAttributes(
735
comp(),
736
cpIndex,
737
&dataAddress,
738
&type,
739
&isVolatile,
740
&isFinal,
741
&isPrivate,
742
false,
743
&isUnresolvedInCP);
744
745
TR::KnownObjectTable::Index knownObjectIndex = TR::KnownObjectTable::UNKNOWN;
746
if (resolved && isFinal && type == TR::Address)
747
{
748
knownObjectIndex = TR::TransformUtil::knownObjectFromFinalStatic(
749
comp(), owningMethod, cpIndex, dataAddress);
750
}
751
752
if (knownObjectIndex != TR::KnownObjectTable::UNKNOWN)
753
push(new (trStackMemory()) KnownObjOperand(knownObjectIndex));
754
else
755
pushUnknownOperand();
756
}
757
758
void
759
InterpreterEmulator::maintainStackForAload(int slotIndex)
760
{
761
TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");
762
763
push((*_currentLocalObjectInfo)[slotIndex]);
764
}
765
766
void
767
InterpreterEmulator::maintainStackForAstore(int slotIndex)
768
{
769
TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");
770
(*_currentLocalObjectInfo)[slotIndex] = pop();
771
}
772
773
void
774
InterpreterEmulator::maintainStackForldc(int32_t cpIndex)
775
{
776
TR::DataType type = method()->getLDCType(cpIndex);
777
switch (type)
778
{
779
case TR::Address:
780
// TODO: should add a function to check if cp entry is unresolved for all constant
781
// not just for string. Currently only do it for string because it may be patched
782
// to a different object in OpenJDK MethodHandle implementation
783
//
784
if (method()->isStringConstant(cpIndex) && !method()->isUnresolvedString(cpIndex))
785
{
786
uintptr_t * location = (uintptr_t *)method()->stringConstant(cpIndex);
787
TR::KnownObjectTable *knot = comp()->getKnownObjectTable();
788
if (knot)
789
{
790
TR::KnownObjectTable::Index koi = knot->getOrCreateIndexAt(location);
791
push(new (trStackMemory()) KnownObjOperand(koi));
792
debugTrace(tracer(), "aload known obj%d from ldc %d", koi, cpIndex);
793
return;
794
}
795
}
796
break;
797
default:
798
break;
799
}
800
801
pushUnknownOperand();
802
}
803
804
void
805
InterpreterEmulator::maintainStackForCall(Operand *result, int32_t numArgs, TR::DataType returnType)
806
{
807
TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");
808
809
for (int i = 1; i <= numArgs; i++)
810
pop();
811
812
if (result)
813
push(result);
814
else if (returnType != TR::NoType)
815
pushUnknownOperand();
816
}
817
818
void
819
InterpreterEmulator::maintainStackForCall()
820
{
821
TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");
822
int32_t numOfArgs = 0;
823
TR::DataType returnType = TR::NoType;
824
Operand* result = NULL;
825
826
if (_currentCallMethod)
827
result = getReturnValue(_currentCallMethod);
828
829
// If the caller is thunk archetype, the load of parm `argPlaceholder` can
830
// be expanded to loads of multiple arguments, so we can't pop the number
831
// of arguments of a refined call
832
//
833
if (_currentCallSite && !_callerIsThunkArchetype)
834
{
835
if (_currentCallSite->_isInterface)
836
{
837
numOfArgs = _currentCallSite->_interfaceMethod->numberOfExplicitParameters() + 1;
838
returnType = _currentCallSite->_interfaceMethod->returnType();
839
}
840
else if (_currentCallSite->_initialCalleeMethod)
841
{
842
numOfArgs = _currentCallSite->_initialCalleeMethod->numberOfParameters();
843
returnType = _currentCallSite->_initialCalleeMethod->returnType();
844
}
845
}
846
else
847
{
848
int32_t cpIndex = next2Bytes();
849
bool isStatic = false;
850
switch (current())
851
{
852
case J9BCinvokespecialsplit:
853
cpIndex |= J9_SPECIAL_SPLIT_TABLE_INDEX_FLAG;
854
break;
855
case J9BCinvokestaticsplit:
856
cpIndex |= J9_STATIC_SPLIT_TABLE_INDEX_FLAG;
857
case J9BCinvokestatic:
858
isStatic = true;
859
break;
860
case J9BCinvokedynamic:
861
case J9BCinvokehandle:
862
TR_ASSERT_FATAL(false, "Can't maintain stack for unresolved invokehandle");
863
break;
864
865
default:
866
break;
867
}
868
TR::Method * calleeMethod = comp()->fej9()->createMethod(trMemory(), _calltarget->_calleeMethod->containingClass(), cpIndex);
869
numOfArgs = calleeMethod->numberOfExplicitParameters() + (isStatic ? 0 : 1);
870
returnType = calleeMethod->returnType();
871
}
872
maintainStackForCall(result, numOfArgs, returnType);
873
}
874
875
void
876
InterpreterEmulator::dumpStack()
877
{
878
if (!tracer()->debugLevel())
879
return;
880
881
debugTrace(tracer(), "operandStack after bytecode %d : %s ", _bcIndex, comp()->fej9()->getByteCodeName(nextByte(0)));
882
for (int i = 0; i < _stack->size(); i++ )
883
{
884
Operand *x = (*_stack)[i];
885
_operandBuf->clear();
886
x->printToString(_operandBuf);
887
debugTrace(tracer(), "[%d]=%s", i, _operandBuf->text());
888
}
889
}
890
891
Operand *
892
InterpreterEmulator::getReturnValue(TR_ResolvedMethod *callee)
893
{
894
if (!callee)
895
return NULL;
896
Operand *result = NULL;
897
TR::RecognizedMethod recognizedMethod = callee->getRecognizedMethod();
898
TR::KnownObjectTable *knot = comp()->getKnownObjectTable();
899
900
TR::IlGeneratorMethodDetails & details = comp()->ilGenRequest().details();
901
if (_callerIsThunkArchetype && details.isMethodHandleThunk())
902
{
903
J9::MethodHandleThunkDetails & thunkDetails = static_cast<J9::MethodHandleThunkDetails &>(details);
904
if (!thunkDetails.isCustom())
905
recognizedMethod = TR::unknownMethod;
906
}
907
908
switch (recognizedMethod)
909
{
910
case TR::java_lang_invoke_ILGenMacros_isCustomThunk:
911
result = new (trStackMemory()) IconstOperand(1);
912
break;
913
case TR::java_lang_invoke_ILGenMacros_isShareableThunk:
914
result = new (trStackMemory()) IconstOperand(0);
915
break;
916
917
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
918
case TR::java_lang_invoke_DelegatingMethodHandle_getTarget:
919
{
920
TR::KnownObjectTable::Index dmhIndex = top()->getKnownObjectIndex();
921
bool trace = tracer()->debugLevel();
922
TR::KnownObjectTable::Index targetIndex =
923
comp()->fej9()->delegatingMethodHandleTarget(comp(), dmhIndex, trace);
924
925
if (targetIndex == TR::KnownObjectTable::UNKNOWN)
926
return NULL;
927
928
result = new (trStackMemory()) KnownObjOperand(targetIndex);
929
break;
930
}
931
#endif
932
933
case TR::java_lang_invoke_MutableCallSite_getTarget:
934
case TR::java_lang_invoke_Invokers_getCallSiteTarget:
935
{
936
// The CallSite object is always topmost on the stack.
937
TR::KnownObjectTable::Index callSiteIndex = top()->getKnownObjectIndex();
938
if (callSiteIndex == TR::KnownObjectTable::UNKNOWN)
939
return NULL;
940
941
TR::KnownObjectTable::Index resultIndex = TR::KnownObjectTable::UNKNOWN;
942
const char * const mcsClassName = "java/lang/invoke/MutableCallSite";
943
const int mcsClassNameLen = (int)strlen(mcsClassName);
944
TR_OpaqueClassBlock *mutableCallsiteClass =
945
fe()->getSystemClassFromClassName(mcsClassName, mcsClassNameLen, true);
946
947
debugTrace(tracer(), "potential MCS target: call site obj%d(*%p) mutableCallsiteClass %p\n", callSiteIndex, knot->getPointerLocation(callSiteIndex), mutableCallsiteClass);
948
if (mutableCallsiteClass)
949
{
950
if (recognizedMethod != TR::java_lang_invoke_MutableCallSite_getTarget)
951
{
952
TR_OpaqueClassBlock *callSiteType =
953
fe()->getObjectClassFromKnownObjectIndex(comp(), callSiteIndex);
954
if (callSiteType == NULL)
955
{
956
debugTrace(tracer(), "failed to determine concrete CallSite type");
957
return NULL;
958
}
959
else if (fe()->isInstanceOf(callSiteType, mutableCallsiteClass, true) != TR_yes)
960
{
961
debugTrace(tracer(), "not a MutableCallSite");
962
return NULL;
963
}
964
}
965
966
#if defined(J9VM_OPT_JITSERVER)
967
if (comp()->isOutOfProcessCompilation())
968
{
969
auto stream = TR::CompilationInfo::getStream();
970
stream->write(JITServer::MessageType::KnownObjectTable_dereferenceKnownObjectField2, mutableCallsiteClass, callSiteIndex);
971
972
auto recv = stream->read<TR::KnownObjectTable::Index, uintptr_t*>();
973
resultIndex = std::get<0>(recv);
974
uintptr_t *objectPointerReference = std::get<1>(recv);
975
976
if (resultIndex != TR::KnownObjectTable::UNKNOWN)
977
{
978
knot->updateKnownObjectTableAtServer(resultIndex, objectPointerReference);
979
}
980
result = new (trStackMemory()) MutableCallsiteTargetOperand(resultIndex, callSiteIndex);
981
}
982
else
983
#endif /* defined(J9VM_OPT_JITSERVER) */
984
{
985
TR::VMAccessCriticalSection dereferenceKnownObjectField(comp()->fej9());
986
int32_t targetFieldOffset = comp()->fej9()->getInstanceFieldOffset(mutableCallsiteClass, "target", "Ljava/lang/invoke/MethodHandle;");
987
uintptr_t receiverAddress = knot->getPointer(callSiteIndex);
988
TR_OpaqueClassBlock *receiverClass = comp()->fej9()->getObjectClass(receiverAddress);
989
TR_ASSERT_FATAL(comp()->fej9()->isInstanceOf(receiverClass, mutableCallsiteClass, true) == TR_yes, "receiver of mutableCallsite_getTarget must be instance of MutableCallSite (*%p)", knot->getPointerLocation(callSiteIndex));
990
uintptr_t fieldAddress = comp()->fej9()->getReferenceFieldAt(receiverAddress, targetFieldOffset);
991
resultIndex = knot->getOrCreateIndex(fieldAddress);
992
result = new (trStackMemory()) MutableCallsiteTargetOperand(resultIndex, callSiteIndex);
993
}
994
}
995
}
996
break;
997
case TR::java_lang_invoke_DirectMethodHandle_internalMemberName:
998
case TR::java_lang_invoke_DirectMethodHandle_internalMemberNameEnsureInit:
999
{
1000
Operand* mh = top();
1001
TR::KnownObjectTable::Index mhIndex = top()->getKnownObjectIndex();
1002
debugTrace(tracer(), "Known DirectMethodHandle koi %d\n", mhIndex);
1003
TR::KnownObjectTable *knot = comp()->getKnownObjectTable();
1004
if (knot && mhIndex != TR::KnownObjectTable::UNKNOWN && !knot->isNull(mhIndex))
1005
{
1006
TR::KnownObjectTable::Index memberIndex = comp()->fej9()->getMemberNameFieldKnotIndexFromMethodHandleKnotIndex(comp(), mhIndex, "member");
1007
debugTrace(tracer(), "Known internal member name koi %d\n", memberIndex);
1008
result = new (trStackMemory()) KnownObjOperand(memberIndex);
1009
}
1010
break;
1011
}
1012
case TR::java_lang_invoke_DirectMethodHandle_constructorMethod:
1013
{
1014
Operand* mh = top();
1015
TR::KnownObjectTable::Index mhIndex = top()->getKnownObjectIndex();
1016
debugTrace(tracer(), "Known DirectMethodHandle koi %d\n", mhIndex);
1017
TR::KnownObjectTable *knot = comp()->getKnownObjectTable();
1018
if (knot && mhIndex != TR::KnownObjectTable::UNKNOWN && !knot->isNull(mhIndex))
1019
{
1020
TR::KnownObjectTable::Index memberIndex = comp()->fej9()->getMemberNameFieldKnotIndexFromMethodHandleKnotIndex(comp(), mhIndex, "initMethod");
1021
debugTrace(tracer(), "Known internal member name koi %d\n", memberIndex);
1022
result = new (trStackMemory()) KnownObjOperand(memberIndex);
1023
}
1024
break;
1025
}
1026
1027
default:
1028
break;
1029
}
1030
return result;
1031
}
1032
1033
void
1034
InterpreterEmulator::refineResolvedCalleeForInvokestatic(TR_ResolvedMethod *&callee, TR::KnownObjectTable::Index & mcsIndex, TR::KnownObjectTable::Index & mhIndex, bool &isIndirectCall)
1035
{
1036
TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");
1037
if (!comp()->getOrCreateKnownObjectTable())
1038
return;
1039
1040
bool isVirtual = false;
1041
TR::RecognizedMethod rm = callee->getRecognizedMethod();
1042
switch (rm)
1043
{
1044
// refine the ILGenMacros_invokeExact* callees
1045
case TR::java_lang_invoke_ILGenMacros_invokeExact:
1046
case TR::java_lang_invoke_ILGenMacros_invokeExact_X:
1047
case TR::java_lang_invoke_ILGenMacros_invokeExactAndFixup:
1048
{
1049
int argNum = callee->numberOfExplicitParameters();
1050
if (argNum > 0)
1051
{
1052
Operand *operand = topn(argNum-1); // for the ILGenMacros_invokeExact* methods, the first argument is always the methodhandle object
1053
MutableCallsiteTargetOperand * mcsOperand = operand->asMutableCallsiteTargetOperand();
1054
if (mcsOperand)
1055
{
1056
mhIndex = mcsOperand->getMethodHandleIndex();
1057
mcsIndex = mcsOperand->getMutableCallsiteIndex();
1058
}
1059
else
1060
mhIndex = operand->getKnownObjectIndex();
1061
}
1062
1063
if (mhIndex != TR::KnownObjectTable::UNKNOWN)
1064
{
1065
debugTrace(tracer(), "refine java_lang_invoke_MethodHandle_invokeExact with obj%d to archetype specimen at bcIndex=%d\n", mhIndex, _bcIndex);
1066
callee = comp()->fej9()->createMethodHandleArchetypeSpecimen(this->trMemory(), comp()->getKnownObjectTable()->getPointerLocation(mhIndex), _calltarget->_calleeMethod);
1067
}
1068
return;
1069
}
1070
// refine the leaf method handle callees
1071
case TR::java_lang_invoke_VirtualHandle_virtualCall:
1072
isVirtual = true;
1073
case TR::java_lang_invoke_DirectHandle_directCall:
1074
{
1075
TR_J9VMBase *fej9 = comp()->fej9();
1076
TR_J9VMBase::MethodOfHandle moh = fej9->methodOfDirectOrVirtualHandle(
1077
_calltarget->_calleeMethod->getMethodHandleLocation(), isVirtual);
1078
1079
TR_ASSERT_FATAL(moh.j9method != NULL, "Must have a j9method to generate a custom call");
1080
uint32_t vTableSlot = isVirtual ? (uint32_t)moh.vmSlot : 0;
1081
TR_ResolvedMethod *newCallee = fej9->createResolvedMethodWithVTableSlot(
1082
trMemory(), vTableSlot, moh.j9method, _calltarget->_calleeMethod);
1083
1084
// Don't refine virtualCall to an interface method, which will confuse
1085
// the virtual call site logic in visitInvokestatic()
1086
TR_OpaqueClassBlock *defClass = newCallee->classOfMethod();
1087
if (isVirtual && TR::Compiler->cls.isInterfaceClass(comp(), defClass))
1088
return;
1089
1090
isIndirectCall = isVirtual;
1091
callee = newCallee;
1092
return;
1093
}
1094
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
1095
case TR::java_lang_invoke_MethodHandle_linkToStatic:
1096
case TR::java_lang_invoke_MethodHandle_linkToSpecial:
1097
case TR::java_lang_invoke_MethodHandle_linkToVirtual:
1098
{
1099
TR::KnownObjectTable::Index memberNameIndex = top()->getKnownObjectIndex();
1100
TR_J9VMBase* fej9 = comp()->fej9();
1101
auto targetMethod = fej9->targetMethodFromMemberName(comp(), memberNameIndex);
1102
if (!targetMethod)
1103
return;
1104
1105
uint32_t vTableSlot = 0;
1106
if (rm == TR::java_lang_invoke_MethodHandle_linkToVirtual)
1107
{
1108
uintptr_t slot = fej9->vTableOrITableIndexFromMemberName(comp(), memberNameIndex);
1109
if ((slot & J9_JNI_MID_INTERFACE) == 0)
1110
{
1111
vTableSlot = (uint32_t)slot;
1112
}
1113
else
1114
{
1115
// TODO: Refine to the method identified by the itable slot
1116
// together with the defining (interface) class of the method
1117
// from the MemberName. For such a refinement to matter,
1118
// TR_J9InterfaceCallSite will need to be able to find call
1119
// targets without a CP index.
1120
//
1121
// For the moment, just leave the call unrefined.
1122
//
1123
return;
1124
}
1125
}
1126
1127
// Direct or virtual dispatch. A vTableSlot of 0 indicates a direct
1128
// call, in which case vTableSlot won't really be used as such.
1129
callee = fej9->createResolvedMethodWithVTableSlot(comp()->trMemory(), vTableSlot, targetMethod, _calltarget->_calleeMethod);
1130
1131
isIndirectCall = vTableSlot != 0;
1132
TR_ASSERT_FATAL(
1133
!isIndirectCall
1134
|| rm == TR::java_lang_invoke_MethodHandle_linkToVirtual
1135
|| rm == TR::java_lang_invoke_MethodHandle_linkToInterface,
1136
"indirect linkTo call should only be linkToVirtual or linkToInterface");
1137
1138
heuristicTrace(tracer(), "Refine linkTo to %s\n", callee->signature(trMemory(), stackAlloc));
1139
// The refined method doesn't take MemberName as an argument, pop MemberName out of the operand stack
1140
pop();
1141
return;
1142
}
1143
#endif //J9VM_OPT_OPENJDK_METHODHANDLE
1144
1145
default:
1146
break;
1147
}
1148
}
1149
1150
bool
1151
InterpreterEmulator::findAndCreateCallsitesFromBytecodes(bool wasPeekingSuccessfull, bool withState)
1152
{
1153
heuristicTrace(tracer(),"Find and create callsite %s\n", withState ? "with state" : "without state");
1154
1155
if (withState)
1156
initializeIteratorWithState();
1157
_wasPeekingSuccessfull = wasPeekingSuccessfull;
1158
_currentInlinedBlock = NULL;
1159
TR_J9ByteCode bc = first();
1160
while (bc != J9BCunknown)
1161
{
1162
heuristicTrace(tracer(), "%4d: %s\n", _bcIndex, comp()->fej9()->getByteCodeName(_code[_bcIndex]));
1163
1164
_currentCallSite = NULL;
1165
_currentCallMethod = NULL;
1166
_currentCallMethodUnrefined = NULL;
1167
1168
if (_InterpreterEmulatorFlags[_bcIndex].testAny(InterpreterEmulator::BytecodePropertyFlag::bbStart))
1169
{
1170
_currentInlinedBlock = TR_J9EstimateCodeSize::getBlock(comp(), _blocks, _calltarget->_calleeMethod, _bcIndex, *_cfg);
1171
debugTrace(tracer(),"Found current block %p, number %d for bci %d\n", _currentInlinedBlock, (_currentInlinedBlock) ? _currentInlinedBlock->getNumber() : -1, _bcIndex);
1172
}
1173
1174
1175
TR_ASSERT_FATAL(!isGenerated(_bcIndex), "InterpreterEmulator::findCallsitesFromBytecodes bcIndex %d has been generated\n", _bcIndex);
1176
_newBCInfo->setByteCodeIndex(_bcIndex);
1177
1178
switch (bc)
1179
{
1180
case J9BCinvokedynamic: visitInvokedynamic(); break;
1181
case J9BCinvokevirtual: visitInvokevirtual(); break;
1182
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
1183
case J9BCinvokehandle: visitInvokehandle(); break;
1184
#endif
1185
case J9BCinvokespecial:
1186
case J9BCinvokespecialsplit: visitInvokespecial(); break;
1187
case J9BCinvokestatic:
1188
case J9BCinvokestaticsplit: visitInvokestatic(); break;
1189
case J9BCinvokeinterface: visitInvokeinterface(); break;
1190
1191
default:
1192
break;
1193
}
1194
1195
if (_iteratorWithState)
1196
{
1197
if (maintainStack(bc))
1198
dumpStack();
1199
else
1200
return false;
1201
}
1202
1203
_pca.updateArg(bc);
1204
bc = findNextByteCodeToVisit();
1205
}
1206
1207
heuristicTrace(tracer(), "Finish findAndCreateCallsitesFromBytecodes\n");
1208
return true;
1209
}
1210
1211
TR_J9ByteCode
1212
InterpreterEmulator::findNextByteCodeToVisit()
1213
{
1214
if (!_iteratorWithState)
1215
next();
1216
else
1217
{
1218
setIsGenerated(_bcIndex);
1219
if (_InterpreterEmulatorFlags[_bcIndex].testAny(InterpreterEmulator::BytecodePropertyFlag::isBranch))
1220
{
1221
setIndex(Base::findNextByteCodeToGen());
1222
debugTrace(tracer(), "current bc is branch next bytecode to generate is %d\n", _bcIndex);
1223
}
1224
else next();
1225
}
1226
1227
if (_bcIndex < _maxByteCodeIndex && _InterpreterEmulatorFlags[_bcIndex].testAny(InterpreterEmulator::BytecodePropertyFlag::bbStart))
1228
{
1229
if (isGenerated(_bcIndex))
1230
setIndex(Base::findNextByteCodeToGen());
1231
}
1232
return current();
1233
}
1234
1235
void
1236
InterpreterEmulator::prepareToFindAndCreateCallsites(TR::Block **blocks, flags8_t * flags, TR_CallSite ** callSites, TR::CFG *cfg, TR_ByteCodeInfo *newBCInfo, int32_t recursionDepth, TR_CallStack *callStack)
1237
{
1238
_blocks = blocks;
1239
_InterpreterEmulatorFlags = flags;
1240
_callSites = callSites;
1241
_cfg = cfg;
1242
_newBCInfo = newBCInfo;
1243
_recursionDepth = recursionDepth;
1244
_callStack = callStack;
1245
_nonColdCallExists = false;
1246
_inlineableCallExists = false;
1247
}
1248
1249
void
1250
InterpreterEmulator::visitInvokedynamic()
1251
{
1252
TR_ResolvedJ9Method * owningMethod = static_cast<TR_ResolvedJ9Method*>(_methodSymbol->getResolvedMethod());
1253
int32_t callSiteIndex = next2Bytes();
1254
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
1255
if (owningMethod->isUnresolvedCallSiteTableEntry(callSiteIndex)
1256
|| comp()->compileRelocatableCode()
1257
) return; // do nothing if unresolved, is AOT compilation
1258
uintptr_t * invokeCacheArray = (uintptr_t *) owningMethod->callSiteTableEntryAddress(callSiteIndex);
1259
updateKnotAndCreateCallSiteUsingInvokeCacheArray(owningMethod, invokeCacheArray, -1);
1260
#else
1261
bool isInterface = false;
1262
bool isIndirectCall = false;
1263
TR::Method *interfaceMethod = 0;
1264
TR::TreeTop *callNodeTreeTop = 0;
1265
TR::Node *parent = 0;
1266
TR::Node *callNode = 0;
1267
TR::ResolvedMethodSymbol *resolvedSymbol = 0;
1268
Operand *result = NULL;
1269
TR::KnownObjectTable *knot = comp()->getOrCreateKnownObjectTable();
1270
if (knot && !owningMethod->isUnresolvedCallSiteTableEntry(callSiteIndex))
1271
{
1272
isIndirectCall = true;
1273
uintptr_t *entryLocation = (uintptr_t*)owningMethod->callSiteTableEntryAddress(callSiteIndex);
1274
// Add callsite handle to known object table
1275
knot->getOrCreateIndexAt((uintptr_t*)entryLocation);
1276
_currentCallMethod = comp()->fej9()->createMethodHandleArchetypeSpecimen(this->trMemory(), entryLocation, owningMethod);
1277
_currentCallMethodUnrefined = _currentCallMethod;
1278
bool allconsts= false;
1279
1280
heuristicTrace(tracer(),"numberOfExplicitParameters = %d _pca.getNumPrevConstArgs = %d\n", _currentCallMethod->numberOfExplicitParameters() , _pca.getNumPrevConstArgs(_currentCallMethod->numberOfExplicitParameters()));
1281
if (_currentCallMethod->numberOfExplicitParameters() > 0 && _currentCallMethod->numberOfExplicitParameters() <= _pca.getNumPrevConstArgs(_currentCallMethod->numberOfExplicitParameters()))
1282
allconsts = true;
1283
1284
TR_CallSite *callsite = new (comp()->trHeapMemory()) TR_J9MethodHandleCallSite(_calltarget->_calleeMethod, callNodeTreeTop, parent,
1285
callNode, interfaceMethod, _currentCallMethod->classOfMethod(),
1286
-1, -1, _currentCallMethod,
1287
resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo, comp(),
1288
_recursionDepth, allconsts);
1289
1290
findTargetAndUpdateInfoForCallsite(callsite);
1291
}
1292
#endif //J9VM_OPT_OPENJDK_METHODHANDLE
1293
}
1294
1295
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
1296
void
1297
InterpreterEmulator::visitInvokehandle()
1298
{
1299
int32_t cpIndex = next2Bytes();
1300
TR_ResolvedJ9Method * owningMethod = static_cast<TR_ResolvedJ9Method*>(_methodSymbol->getResolvedMethod());
1301
if (owningMethod->isUnresolvedMethodTypeTableEntry(cpIndex)
1302
|| comp()->compileRelocatableCode()
1303
) return; // do nothing if unresolved, is an AOT compilation
1304
uintptr_t * invokeCacheArray = (uintptr_t *) owningMethod->methodTypeTableEntryAddress(cpIndex);
1305
updateKnotAndCreateCallSiteUsingInvokeCacheArray(owningMethod, invokeCacheArray, cpIndex);
1306
}
1307
1308
void
1309
InterpreterEmulator::updateKnotAndCreateCallSiteUsingInvokeCacheArray(TR_ResolvedJ9Method* owningMethod, uintptr_t * invokeCacheArray, int32_t cpIndex)
1310
{
1311
TR_J9VMBase *fej9 = comp()->fej9();
1312
TR::KnownObjectTable::Index idx = fej9->getKnotIndexOfInvokeCacheArrayAppendixElement(comp(), invokeCacheArray);
1313
if (_iteratorWithState)
1314
{
1315
if (idx != TR::KnownObjectTable::UNKNOWN)
1316
push(new (trStackMemory()) KnownObjOperand(idx));
1317
else
1318
pushUnknownOperand();
1319
}
1320
1321
TR_ResolvedMethod * targetMethod = fej9->targetMethodFromInvokeCacheArrayMemberNameObj(comp(), owningMethod, invokeCacheArray);
1322
bool isInterface = false;
1323
bool isIndirectCall = false;
1324
TR::Method *interfaceMethod = 0;
1325
TR::TreeTop *callNodeTreeTop = 0;
1326
TR::Node *parent = 0;
1327
TR::Node *callNode = 0;
1328
TR::ResolvedMethodSymbol *resolvedSymbol = 0;
1329
TR::KnownObjectTable *knot = comp()->getOrCreateKnownObjectTable();
1330
bool allconsts = false;
1331
if (targetMethod->numberOfExplicitParameters() > 0 && targetMethod->numberOfExplicitParameters() <= _pca.getNumPrevConstArgs(targetMethod->numberOfExplicitParameters()))
1332
allconsts = true;
1333
TR_CallSite *callsite = new (comp()->trHeapMemory()) TR_DirectCallSite(_calltarget->_calleeMethod, callNodeTreeTop, parent,
1334
callNode, interfaceMethod, targetMethod->classOfMethod(),
1335
-1, cpIndex, targetMethod,
1336
resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo, comp(),
1337
_recursionDepth, allconsts);
1338
1339
findTargetAndUpdateInfoForCallsite(callsite, idx);
1340
}
1341
1342
#endif //J9VM_OPT_OPENJDK_METHODHANDLE
1343
1344
bool
1345
InterpreterEmulator::isCurrentCallUnresolvedOrCold(TR_ResolvedMethod *resolvedMethod, bool isUnresolvedInCP)
1346
{
1347
if (!resolvedMethod)
1348
return true;
1349
1350
bool isIndirectCall = false;
1351
if (current() == J9BCinvokevirtual)
1352
isIndirectCall = true;
1353
1354
// Since bytecodes in a thunk archetype are never interpreted,
1355
// most of the cp entries may appear unresolved, and we always
1356
// compile-time resolve the cp entries. Thus ignore resolution
1357
// status of cp entries of thunk arthetype
1358
//
1359
if (_callerIsThunkArchetype)
1360
return resolvedMethod->isCold(comp(), isIndirectCall);
1361
else
1362
return (isUnresolvedInCP || resolvedMethod->isCold(comp(), isIndirectCall));
1363
}
1364
1365
void
1366
InterpreterEmulator::debugUnresolvedOrCold(TR_ResolvedMethod *resolvedMethod)
1367
{
1368
int32_t cpIndex = next2Bytes();
1369
if(tracer()->heuristicLevel())
1370
{
1371
if (resolvedMethod)
1372
heuristicTrace(tracer(), "Depth %d: Call at bc index %d is Cold. Not searching for targets. Signature %s", _recursionDepth, _bcIndex, resolvedMethod->signature(comp()->trMemory()));
1373
else
1374
{
1375
switch (current())
1376
{
1377
case J9BCinvokespecialsplit:
1378
cpIndex |= J9_SPECIAL_SPLIT_TABLE_INDEX_FLAG;
1379
break;
1380
case J9BCinvokestaticsplit:
1381
cpIndex |= J9_STATIC_SPLIT_TABLE_INDEX_FLAG;
1382
break;
1383
1384
default:
1385
break;
1386
}
1387
TR::Method *meth = comp()->fej9()->createMethod(this->trMemory(), _calltarget->_calleeMethod->containingClass(), cpIndex);
1388
heuristicTrace(tracer(), "Depth %d: Call at bc index %d is Cold. Not searching for targets. Signature %s", _recursionDepth, _bcIndex, meth->signature(comp()->trMemory()));
1389
}
1390
}
1391
}
1392
1393
void
1394
InterpreterEmulator::refineResolvedCalleeForInvokevirtual(TR_ResolvedMethod *&callee, bool &isIndirectCall)
1395
{
1396
TR_ASSERT_FATAL(_iteratorWithState, "has to be called when the iterator has state!");
1397
if (!comp()->getOrCreateKnownObjectTable())
1398
return;
1399
1400
TR::RecognizedMethod rm = callee->getRecognizedMethod();
1401
switch (rm)
1402
{
1403
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
1404
case TR::java_lang_invoke_MethodHandle_invokeBasic:
1405
{
1406
int argNum = callee->numberOfExplicitParameters();
1407
TR::KnownObjectTable::Index receiverIndex = topn(argNum)->getKnownObjectIndex();
1408
TR_J9VMBase* fej9 = comp()->fej9();
1409
auto targetMethod = fej9->targetMethodFromMethodHandle(comp(), receiverIndex);
1410
if (!targetMethod) return;
1411
1412
isIndirectCall = false;
1413
callee = fej9->createResolvedMethod(comp()->trMemory(), targetMethod, callee->owningMethod());
1414
heuristicTrace(tracer(), "Refine invokeBasic to %s\n", callee->signature(trMemory(), stackAlloc));
1415
return;
1416
}
1417
#endif //J9VM_OPT_OPENJDK_METHODHANDLE
1418
default:
1419
return;
1420
}
1421
}
1422
1423
void
1424
InterpreterEmulator::visitInvokevirtual()
1425
{
1426
int32_t cpIndex = next2Bytes();
1427
auto calleeMethod = (TR_ResolvedJ9Method*)_calltarget->_calleeMethod;
1428
bool isUnresolvedInCP;
1429
// Calls in thunk archetype won't be executed by interpreter, so they may appear as unresolved
1430
bool ignoreRtResolve = _callerIsThunkArchetype;
1431
_currentCallMethod = calleeMethod->getResolvedPossiblyPrivateVirtualMethod(comp(), cpIndex, ignoreRtResolve, &isUnresolvedInCP);
1432
_currentCallMethodUnrefined = _currentCallMethod;
1433
Operand *result = NULL;
1434
if (isCurrentCallUnresolvedOrCold(_currentCallMethod, isUnresolvedInCP))
1435
{
1436
debugUnresolvedOrCold(_currentCallMethod);
1437
}
1438
else if (_currentCallMethod)
1439
{
1440
bool isIndirectCall = !_currentCallMethod->isFinal() && !_currentCallMethod->isPrivate();
1441
if (_iteratorWithState)
1442
refineResolvedCalleeForInvokevirtual(_currentCallMethod, isIndirectCall);
1443
1444
// Customization logic is not needed in customized thunk or in inlining
1445
// with known MethodHandle object
1446
// Since branch folding is disabled and we're ignoring the coldness info
1447
// in thunk archetype, calls to the following method will be added to the
1448
// call site list and take up some inlining budget, causing less methods
1449
// to be inlined. Don't create call site for them
1450
//
1451
switch (_currentCallMethod->getRecognizedMethod())
1452
{
1453
case TR::java_lang_invoke_MethodHandle_doCustomizationLogic:
1454
case TR::java_lang_invoke_MethodHandle_undoCustomizationLogic:
1455
if (_callerIsThunkArchetype)
1456
return;
1457
1458
default:
1459
break;
1460
}
1461
1462
bool allconsts= false;
1463
heuristicTrace(tracer(),"numberOfExplicitParameters = %d _pca.getNumPrevConstArgs = %d\n",_currentCallMethod->numberOfExplicitParameters() ,_pca.getNumPrevConstArgs(_currentCallMethod->numberOfExplicitParameters()));
1464
if ( _currentCallMethod->numberOfExplicitParameters() > 0 && _currentCallMethod->numberOfExplicitParameters() <= _pca.getNumPrevConstArgs(_currentCallMethod->numberOfExplicitParameters()))
1465
allconsts = true;
1466
1467
TR_CallSite *callsite;
1468
bool isInterface = false;
1469
TR::Method *interfaceMethod = 0;
1470
TR::TreeTop *callNodeTreeTop = 0;
1471
TR::Node *parent = 0;
1472
TR::Node *callNode = 0;
1473
TR::ResolvedMethodSymbol *resolvedSymbol = 0;
1474
1475
Operand *receiver = NULL;
1476
if (_iteratorWithState)
1477
receiver = topn(_currentCallMethodUnrefined->numberOfExplicitParameters());
1478
1479
if (_currentCallMethod->convertToMethod()->isArchetypeSpecimen() && _currentCallMethod->getMethodHandleLocation())
1480
{
1481
callsite = new (comp()->trHeapMemory()) TR_J9MethodHandleCallSite(_calltarget->_calleeMethod, callNodeTreeTop, parent,
1482
callNode, interfaceMethod, _currentCallMethod->classOfMethod(),
1483
-1, cpIndex, _currentCallMethod,
1484
resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo, comp(),
1485
_recursionDepth, allconsts);
1486
}
1487
else if (_currentCallMethod->getRecognizedMethod() == TR::java_lang_invoke_MethodHandle_invokeExact
1488
|| (_currentCallMethod->getRecognizedMethod() == TR::java_lang_invoke_MethodHandle_invokeBasic
1489
&& receiver != NULL && receiver->asMutableCallsiteTargetOperand() != NULL))
1490
{
1491
TR_J9MutableCallSite *inlinerMcs = new (comp()->trHeapMemory()) TR_J9MutableCallSite(_calltarget->_calleeMethod, callNodeTreeTop, parent,
1492
callNode, interfaceMethod, _currentCallMethod->classOfMethod(),
1493
(int32_t) _currentCallMethod->virtualCallSelector(cpIndex), cpIndex, _currentCallMethod,
1494
resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo, comp(),
1495
_recursionDepth, allconsts);
1496
if (_currentCallMethod->getRecognizedMethod() == TR::java_lang_invoke_MethodHandle_invokeBasic)
1497
{
1498
// Set the MCS reference location so that TR_J9MutableCallSite
1499
// doesn't go rummaging through the trees (with
1500
// isMutableCallSiteTargetInvokeExact()) looking for
1501
// mcs.target.invokeExact() or mcs.getTarget().invokeExact(). Those
1502
// patterns won't be found:
1503
// - the final call is invokeBasic(), not invokeExact()
1504
// - rather than a load or getTarget() call, the target will come
1505
// from Invokers.getCallSiteTarget() (or, once inlining works for
1506
// dynamic invoker handles, another invokeBasic())
1507
//
1508
// But there's no need to look through the trees anyway, since the
1509
// MCS is already known at this point.
1510
1511
TR::KnownObjectTable *knot = comp()->getOrCreateKnownObjectTable();
1512
MutableCallsiteTargetOperand *mcsOperand = receiver->asMutableCallsiteTargetOperand();
1513
TR::KnownObjectTable::Index mcsIndex = mcsOperand->getMutableCallsiteIndex();
1514
inlinerMcs->setMCSReferenceLocation(knot->getPointerLocation(mcsIndex));
1515
}
1516
1517
callsite = inlinerMcs;
1518
}
1519
else if (isIndirectCall)
1520
{
1521
callsite = new (comp()->trHeapMemory()) TR_J9VirtualCallSite(_calltarget->_calleeMethod, callNodeTreeTop, parent,
1522
callNode, interfaceMethod, _currentCallMethod->classOfMethod(),
1523
(int32_t) _currentCallMethod->virtualCallSelector(cpIndex), cpIndex, _currentCallMethod,
1524
resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo, comp(),
1525
_recursionDepth, allconsts);
1526
1527
}
1528
else
1529
{
1530
callsite = new (comp()->trHeapMemory()) TR_DirectCallSite(_calltarget->_calleeMethod, callNodeTreeTop, parent,
1531
callNode, interfaceMethod, _currentCallMethod->classOfMethod(),
1532
-1, cpIndex, _currentCallMethod,
1533
resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo, comp(),
1534
_recursionDepth, allconsts);
1535
1536
}
1537
1538
if(tracer()->debugLevel())
1539
_pca.printIndexes(comp());
1540
findTargetAndUpdateInfoForCallsite(callsite);
1541
}
1542
1543
}
1544
1545
void
1546
InterpreterEmulator::visitInvokespecial()
1547
{
1548
int32_t cpIndex = next2Bytes();
1549
bool isUnresolvedInCP;
1550
_currentCallMethod = _calltarget->_calleeMethod->getResolvedSpecialMethod(comp(), (current() == J9BCinvokespecialsplit)?cpIndex |= J9_SPECIAL_SPLIT_TABLE_INDEX_FLAG:cpIndex, &isUnresolvedInCP);
1551
_currentCallMethodUnrefined = _currentCallMethod;
1552
if (isCurrentCallUnresolvedOrCold(_currentCallMethod, isUnresolvedInCP))
1553
{
1554
debugUnresolvedOrCold(_currentCallMethod);
1555
}
1556
else
1557
{
1558
bool allconsts= false;
1559
heuristicTrace(tracer(),"numberOfExplicitParameters = %d _pca.getNumPrevConstArgs = %d\n",_currentCallMethod->numberOfExplicitParameters() ,_pca.getNumPrevConstArgs(_currentCallMethod->numberOfExplicitParameters()));
1560
if (_currentCallMethod->numberOfExplicitParameters() > 0 && _currentCallMethod->numberOfExplicitParameters() <= _pca.getNumPrevConstArgs(_currentCallMethod->numberOfExplicitParameters()))
1561
allconsts = true;
1562
1563
bool isIndirectCall = false;
1564
bool isInterface = false;
1565
TR::Method *interfaceMethod = 0;
1566
TR::TreeTop *callNodeTreeTop = 0;
1567
TR::Node *parent = 0;
1568
TR::Node *callNode = 0;
1569
TR::ResolvedMethodSymbol *resolvedSymbol = 0;
1570
TR_CallSite *callsite = new (comp()->trHeapMemory()) TR_DirectCallSite(_calltarget->_calleeMethod, callNodeTreeTop, parent,
1571
callNode, interfaceMethod, _currentCallMethod->classOfMethod(), -1, cpIndex,
1572
_currentCallMethod, resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo, comp(),
1573
_recursionDepth, allconsts);
1574
findTargetAndUpdateInfoForCallsite(callsite);
1575
}
1576
}
1577
1578
void
1579
InterpreterEmulator::visitInvokestatic()
1580
{
1581
int32_t cpIndex = next2Bytes();
1582
bool isUnresolvedInCP;
1583
_currentCallMethod = _calltarget->_calleeMethod->getResolvedStaticMethod(comp(), (current() == J9BCinvokestaticsplit) ? cpIndex |= J9_STATIC_SPLIT_TABLE_INDEX_FLAG:cpIndex, &isUnresolvedInCP);
1584
_currentCallMethodUnrefined = _currentCallMethod;
1585
if (isCurrentCallUnresolvedOrCold(_currentCallMethod, isUnresolvedInCP))
1586
{
1587
debugUnresolvedOrCold(_currentCallMethod);
1588
}
1589
else
1590
{
1591
bool allconsts= false;
1592
1593
heuristicTrace(tracer(),"numberOfExplicitParameters = %d _pca.getNumPrevConstArgs = %d\n",_currentCallMethod->numberOfExplicitParameters() ,_pca.getNumPrevConstArgs(_currentCallMethod->numberOfExplicitParameters()));
1594
if (_currentCallMethod->numberOfExplicitParameters() > 0 && _currentCallMethod->numberOfExplicitParameters() <= _pca.getNumPrevConstArgs(_currentCallMethod->numberOfExplicitParameters()))
1595
allconsts = true;
1596
1597
TR::KnownObjectTable::Index mhIndex = TR::KnownObjectTable::UNKNOWN;
1598
TR::KnownObjectTable::Index mcsIndex = TR::KnownObjectTable::UNKNOWN;
1599
bool isIndirectCall = false;
1600
if (_iteratorWithState)
1601
refineResolvedCalleeForInvokestatic(_currentCallMethod, mcsIndex, mhIndex, isIndirectCall);
1602
1603
bool isInterface = false;
1604
TR_CallSite *callsite = NULL;
1605
TR::Method *interfaceMethod = 0;
1606
TR::TreeTop *callNodeTreeTop = 0;
1607
TR::Node *parent = 0;
1608
TR::Node *callNode = 0;
1609
TR::ResolvedMethodSymbol *resolvedSymbol = 0;
1610
1611
if (_currentCallMethod->convertToMethod()->isArchetypeSpecimen() &&
1612
_currentCallMethod->getMethodHandleLocation() &&
1613
mcsIndex == TR::KnownObjectTable::UNKNOWN)
1614
{
1615
callsite = new (comp()->trHeapMemory()) TR_J9MethodHandleCallSite( _calltarget->_calleeMethod, callNodeTreeTop, parent,
1616
callNode, interfaceMethod, _currentCallMethod->classOfMethod(),
1617
-1, cpIndex, _currentCallMethod,
1618
resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo, comp(),
1619
_recursionDepth, allconsts);
1620
}
1621
else if (_currentCallMethod->convertToMethod()->isArchetypeSpecimen() &&
1622
_currentCallMethod->getMethodHandleLocation() &&
1623
mcsIndex != TR::KnownObjectTable::UNKNOWN)
1624
{
1625
TR_J9MutableCallSite *mcs = new (comp()->trHeapMemory()) TR_J9MutableCallSite( _calltarget->_calleeMethod, callNodeTreeTop, parent,
1626
callNode, interfaceMethod, _currentCallMethod->classOfMethod(),
1627
(int32_t) _currentCallMethod->virtualCallSelector(cpIndex), cpIndex, _currentCallMethod,
1628
resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo, comp(),
1629
_recursionDepth, allconsts);
1630
if (mcsIndex != TR::KnownObjectTable::UNKNOWN)
1631
{
1632
if (comp()->getKnownObjectTable())
1633
mcs->setMCSReferenceLocation(comp()->getKnownObjectTable()->getPointerLocation(mcsIndex));
1634
}
1635
callsite = mcs;
1636
}
1637
else if (isIndirectCall)
1638
{
1639
int32_t noCPIndex = -1; // The method is not referenced via the constant pool
1640
callsite = new (comp()->trHeapMemory()) TR_J9VirtualCallSite(
1641
_calltarget->_calleeMethod, callNodeTreeTop, parent, callNode,
1642
interfaceMethod, _currentCallMethod->classOfMethod(), (int32_t) _currentCallMethod->virtualCallSelector(cpIndex), noCPIndex,
1643
_currentCallMethod, resolvedSymbol, isIndirectCall, isInterface,
1644
*_newBCInfo, comp(), _recursionDepth, allconsts);
1645
}
1646
else
1647
{
1648
callsite = new (comp()->trHeapMemory()) TR_DirectCallSite(_calltarget->_calleeMethod, callNodeTreeTop, parent, callNode, interfaceMethod,
1649
_currentCallMethod->classOfMethod(), -1, cpIndex, _currentCallMethod, resolvedSymbol,
1650
isIndirectCall, isInterface, *_newBCInfo, comp(),
1651
_recursionDepth, allconsts);
1652
}
1653
findTargetAndUpdateInfoForCallsite(callsite);
1654
}
1655
1656
}
1657
1658
void
1659
InterpreterEmulator::visitInvokeinterface()
1660
{
1661
int32_t cpIndex = next2Bytes();
1662
auto calleeMethod = (TR_ResolvedJ9Method*)_calltarget->_calleeMethod;
1663
_currentCallMethod = calleeMethod->getResolvedImproperInterfaceMethod(comp(), cpIndex);
1664
_currentCallMethodUnrefined = _currentCallMethod;
1665
bool isIndirectCall = true;
1666
bool isInterface = true;
1667
if (_currentCallMethod)
1668
{
1669
isInterface = false;
1670
isIndirectCall = !_currentCallMethod->isPrivate() &&
1671
!_currentCallMethod->convertToMethod()->isFinalInObject();
1672
}
1673
1674
TR::Method * interfaceMethod = NULL;
1675
if (isInterface)
1676
interfaceMethod = comp()->fej9()->createMethod(this->trMemory(), _calltarget->_calleeMethod->containingClass(), cpIndex);
1677
1678
TR::TreeTop *callNodeTreeTop = 0;
1679
TR::Node *parent = 0;
1680
TR::Node *callNode = 0;
1681
TR::ResolvedMethodSymbol *resolvedSymbol = 0;
1682
1683
uint32_t explicitParams = 0;
1684
if (isInterface)
1685
explicitParams = interfaceMethod->numberOfExplicitParameters();
1686
else
1687
explicitParams = _currentCallMethod->numberOfExplicitParameters();
1688
1689
bool allconsts= false;
1690
heuristicTrace(tracer(), "numberOfExplicitParameters = %d _pca.getNumPrevConstArgs = %d\n", explicitParams, _pca.getNumPrevConstArgs(explicitParams));
1691
if (explicitParams > 0 && explicitParams <= _pca.getNumPrevConstArgs(explicitParams))
1692
allconsts = true;
1693
1694
TR_CallSite *callsite = NULL;
1695
if (isInterface)
1696
{
1697
TR_OpaqueClassBlock * thisClass = NULL;
1698
callsite = new (comp()->trHeapMemory()) TR_J9InterfaceCallSite(
1699
_calltarget->_calleeMethod, callNodeTreeTop, parent, callNode,
1700
interfaceMethod, thisClass, -1, cpIndex, _currentCallMethod,
1701
resolvedSymbol, isIndirectCall, isInterface, *_newBCInfo,
1702
comp(), _recursionDepth, allconsts);
1703
}
1704
else if (isIndirectCall)
1705
{
1706
callsite = new (comp()->trHeapMemory()) TR_J9VirtualCallSite(
1707
_calltarget->_calleeMethod, callNodeTreeTop, parent, callNode,
1708
interfaceMethod, _currentCallMethod->classOfMethod(), (int32_t) _currentCallMethod->virtualCallSelector(cpIndex), cpIndex,
1709
_currentCallMethod, resolvedSymbol, isIndirectCall, isInterface,
1710
*_newBCInfo, comp(), _recursionDepth, allconsts);
1711
}
1712
else
1713
{
1714
callsite = new (comp()->trHeapMemory()) TR_DirectCallSite(
1715
_calltarget->_calleeMethod, callNodeTreeTop, parent, callNode,
1716
interfaceMethod, _currentCallMethod->classOfMethod(), -1, cpIndex,
1717
_currentCallMethod, resolvedSymbol, isIndirectCall, isInterface,
1718
*_newBCInfo, comp(), _recursionDepth, allconsts);
1719
}
1720
1721
if(tracer()->debugLevel())
1722
{
1723
_pca.printIndexes(comp());
1724
}
1725
findTargetAndUpdateInfoForCallsite(callsite);
1726
}
1727
1728
Operand*
1729
InterpreterEmulator::createOperandFromPrexArg(TR_PrexArgument* prexArgument)
1730
{
1731
auto prexKnowledge = TR_PrexArgument::knowledgeLevel(prexArgument);
1732
switch (prexKnowledge)
1733
{
1734
case KNOWN_OBJECT:
1735
return new (trStackMemory()) KnownObjOperand(prexArgument->getKnownObjectIndex(), prexArgument->getClass());
1736
case FIXED_CLASS:
1737
return new (trStackMemory()) FixedClassOperand(prexArgument->getClass());
1738
case PREEXISTENT:
1739
return new (trStackMemory()) PreexistentObjectOperand(prexArgument->getClass());
1740
case NONE:
1741
return prexArgument->getClass() ? new (trStackMemory()) ObjectOperand(prexArgument->getClass()) : NULL;
1742
}
1743
return NULL;
1744
}
1745
1746
TR_PrexArgument*
1747
InterpreterEmulator::createPrexArgFromOperand(Operand* operand)
1748
{
1749
if (operand->asKnownObject())
1750
{
1751
auto koi = operand->getKnownObjectIndex();
1752
auto knot = comp()->getOrCreateKnownObjectTable();
1753
if (knot && !knot->isNull(koi))
1754
return new (comp()->trHeapMemory()) TR_PrexArgument(operand->getKnownObjectIndex(), comp());
1755
}
1756
else if (operand->asObjectOperand() && operand->asObjectOperand()->getClass())
1757
{
1758
TR_OpaqueClassBlock* clazz = operand->asObjectOperand()->getClass();
1759
TR_PrexArgument::ClassKind kind = TR_PrexArgument::ClassIsUnknown;
1760
if (operand->asFixedClassOperand())
1761
kind = TR_PrexArgument::ClassIsFixed;
1762
else if (operand->asPreexistentObjectOperand())
1763
kind = TR_PrexArgument::ClassIsPreexistent;
1764
1765
return new (comp()->trHeapMemory()) TR_PrexArgument(kind, clazz);
1766
}
1767
1768
return NULL;
1769
}
1770
1771
TR_PrexArgInfo*
1772
InterpreterEmulator::computePrexInfo(
1773
TR_CallSite *callsite, TR::KnownObjectTable::Index appendix)
1774
{
1775
if (tracer()->heuristicLevel())
1776
_ecs->getInliner()->tracer()->dumpCallSite(callsite, "Compute prex info for call site %p\n", callsite);
1777
1778
int32_t numOfArgs = 0;
1779
if (callsite->_isInterface)
1780
{
1781
numOfArgs = callsite->_interfaceMethod->numberOfExplicitParameters() + 1;
1782
}
1783
else if (callsite->_initialCalleeMethod)
1784
{
1785
numOfArgs = callsite->_initialCalleeMethod->numberOfParameters();
1786
}
1787
1788
if (numOfArgs == 0)
1789
return NULL;
1790
1791
// Always favor prex arg from operand if we're iterating with state
1792
// But not for thunk archetype as the method's bytecodes manipulate
1793
// the operand stack differently, and one int `argPlacehowler`
1794
// argument can represent more than one arguments
1795
//
1796
if (!_callerIsThunkArchetype && _iteratorWithState)
1797
{
1798
TR_PrexArgInfo* prexArgInfo = new (comp()->trHeapMemory()) TR_PrexArgInfo(numOfArgs, comp()->trMemory());
1799
for (int32_t i = 0; i < numOfArgs; i++)
1800
{
1801
int32_t posInStack = numOfArgs - i - 1;
1802
prexArgInfo->set(i, createPrexArgFromOperand(topn(posInStack)));
1803
}
1804
1805
if (tracer()->heuristicLevel())
1806
{
1807
alwaysTrace(tracer(), "argInfo from operand stack:");
1808
prexArgInfo->dumpTrace();
1809
}
1810
return prexArgInfo;
1811
}
1812
else if (_wasPeekingSuccessfull)
1813
{
1814
auto callNodeTT = TR_PrexArgInfo::getCallTree(_methodSymbol, callsite, tracer());
1815
if (callNodeTT)
1816
{
1817
// Temporarily set call tree and call node of callsite such that computePrexInfo can use it
1818
callsite->_callNodeTreeTop = callNodeTT;
1819
callsite->_callNode = callNodeTT->getNode()->getChild(0);
1820
auto prexArgInfo = TR_J9InlinerUtil::computePrexInfo(_ecs->getInliner(), callsite, _calltarget->_ecsPrexArgInfo);
1821
1822
// Reset call tree and call node
1823
callsite->_callNodeTreeTop = NULL;
1824
callsite->_callNode = NULL;
1825
return prexArgInfo;
1826
}
1827
}
1828
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
1829
else if (appendix != TR::KnownObjectTable::UNKNOWN)
1830
{
1831
TR_ASSERT_FATAL(!callsite->isIndirectCall(), "appendix with indirect call");
1832
TR_ASSERT_FATAL(
1833
comp()->fej9()->isLambdaFormGeneratedMethod(callsite->_initialCalleeMethod),
1834
"appendix with non-LambdaForm method - expected a call site adapter");
1835
1836
TR::KnownObjectTable *knot = comp()->getKnownObjectTable();
1837
if (!knot->isNull(appendix))
1838
{
1839
TR_PrexArgInfo* prexArgInfo =
1840
new (comp()->trHeapMemory()) TR_PrexArgInfo(numOfArgs, comp()->trMemory());
1841
1842
auto arg = new (comp()->trHeapMemory()) TR_PrexArgument(appendix, comp());
1843
prexArgInfo->set(numOfArgs - 1, arg);
1844
1845
if (tracer()->heuristicLevel())
1846
{
1847
alwaysTrace(tracer(), "argInfo from appendix object:");
1848
prexArgInfo->dumpTrace();
1849
}
1850
1851
return prexArgInfo;
1852
}
1853
}
1854
#endif
1855
1856
return NULL;
1857
}
1858
1859
void
1860
InterpreterEmulator::findTargetAndUpdateInfoForCallsite(
1861
TR_CallSite *callsite, TR::KnownObjectTable::Index appendix)
1862
{
1863
_currentCallSite = callsite;
1864
callsite->_callerBlock = _currentInlinedBlock;
1865
callsite->_ecsPrexArgInfo = computePrexInfo(callsite, appendix);
1866
1867
if (_ecs->isInlineable(_callStack, callsite))
1868
{
1869
_callSites[_bcIndex] = callsite;
1870
_inlineableCallExists = true;
1871
1872
if (!_currentInlinedBlock->isCold())
1873
_nonColdCallExists = true;
1874
1875
for (int i = 0; i < callsite->numTargets(); i++)
1876
callsite->getTarget(i)->_originatingBlock = _currentInlinedBlock;
1877
}
1878
else
1879
{
1880
//support counters
1881
_calltarget->addDeadCallee(callsite);
1882
}
1883
}
1884
1885