Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/optimizer/J9Inliner.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
23
#include "optimizer/Inliner.hpp"
24
#include "optimizer/J9Inliner.hpp"
25
26
#include <algorithm>
27
#include "env/KnownObjectTable.hpp"
28
#include "compile/OSRData.hpp"
29
#include "compile/ResolvedMethod.hpp"
30
#include "env/CompilerEnv.hpp"
31
#include "env/CHTable.hpp"
32
#include "env/PersistentCHTable.hpp"
33
#include "env/VMJ9.h"
34
#include "env/jittypes.h"
35
#include "env/VMAccessCriticalSection.hpp"
36
#include "il/Block.hpp"
37
#include "il/Node.hpp"
38
#include "il/Node_inlines.hpp"
39
#include "il/ParameterSymbol.hpp"
40
#include "il/StaticSymbol.hpp"
41
#include "il/TreeTop.hpp"
42
#include "il/TreeTop_inlines.hpp"
43
#include "optimizer/CallInfo.hpp"
44
#include "optimizer/J9CallGraph.hpp"
45
#include "optimizer/PreExistence.hpp"
46
#include "optimizer/RematTools.hpp"
47
#include "optimizer/Structure.hpp"
48
#include "runtime/J9Profiler.hpp"
49
#include "runtime/J9ValueProfiler.hpp"
50
#include "codegen/CodeGenerator.hpp"
51
#include "ilgen/J9ByteCode.hpp"
52
#include "ilgen/J9ByteCodeIterator.hpp"
53
54
#define OPT_DETAILS "O^O INLINER: "
55
const float MIN_PROFILED_CALL_FREQUENCY = (.65f); // lowered this from .80f since opportunities were being missed in WAS; in those cases getting rid of the call even in 65% of the cases was beneficial probably due to the improved icache impact
56
57
extern int32_t *NumInlinedMethods; // Defined in Inliner.cpp
58
extern int32_t *InlinedSizes; // Defined in Inliner.cpp
59
60
61
//duplicated as long as there are two versions of findInlineTargets
62
static uintptr_t *failMCS(char *reason, TR_CallSite *callSite, TR_InlinerBase* inliner)
63
{
64
debugTrace(inliner->tracer()," Fail isMutableCallSiteTargetInvokeExact(%p): %s", callSite, reason);
65
return NULL;
66
}
67
68
static uintptr_t *isMutableCallSiteTargetInvokeExact(TR_CallSite *callSite, TR_InlinerBase *inliner)
69
{
70
// Looking for either mcs.target.invokeExact(...) or mcs.getTarget().invokeExact(...)
71
// on some known/fixed MutableCallSite object mcs.
72
// Return NULL if it's neither of these.
73
74
if (inliner->comp()->getOption(TR_DisableMutableCallSiteGuards))
75
return NULL;
76
77
TR::Node *callNode = callSite->_callNode;
78
if (!callNode || !callNode->getOpCode().isCall())
79
return failMCS("No call node", callSite, inliner);
80
else if (callNode->getSymbolReference()->isUnresolved())
81
return failMCS("Call symref is unresolved", callSite, inliner);
82
else switch (callNode->getSymbol()->castToResolvedMethodSymbol()->getRecognizedMethod())
83
{
84
case TR::java_lang_invoke_MethodHandle_invokeExact:
85
break;
86
default:
87
return failMCS("Call symref is not invokeExact", callSite, inliner);
88
}
89
90
TR::Node *targetNode = callNode->getChild(callNode->getFirstArgumentIndex());
91
if (!targetNode->getOpCode().hasSymbolReference() || targetNode->getSymbolReference()->isUnresolved())
92
return failMCS("No target symref", callSite, inliner);
93
94
TR::Node *mcsNode = (TR::Node*)(intptr_t)0xdead;
95
if (targetNode->getOpCode().isCall())
96
{
97
switch (targetNode->getSymbol()->castToResolvedMethodSymbol()->getRecognizedMethod())
98
{
99
case TR::java_lang_invoke_MutableCallSite_getTarget:
100
mcsNode = targetNode->getChild(targetNode->getFirstArgumentIndex());
101
break;
102
default:
103
return failMCS("Call receiver isn't a call to getTarget", callSite, inliner);
104
}
105
}
106
else if (targetNode->getOpCode().isLoadIndirect() && targetNode->getDataType() == TR::Address)
107
{
108
switch (targetNode->getSymbol()->getRecognizedField())
109
{
110
case TR::Symbol::Java_lang_invoke_MutableCallSite_target:
111
mcsNode = targetNode->getFirstChild();
112
break;
113
default:
114
return failMCS("Call receiver isn't a load of target field", callSite, inliner);
115
}
116
}
117
else
118
{
119
return failMCS("Unsuitable call receiver", callSite, inliner);
120
}
121
122
if (mcsNode->getSymbolReference()->hasKnownObjectIndex())
123
{
124
uintptr_t *result = mcsNode->getSymbolReference()->getKnownObjectReferenceLocation(inliner->comp());
125
heuristicTrace(inliner->tracer(), " Success: isMutableCallSiteTargetInvokeExact(%p)=%p (obj%d)", callSite, result, mcsNode->getSymbolReference()->getKnownObjectIndex());
126
return result;
127
}
128
else if (mcsNode->getSymbol()->isFixedObjectRef())
129
{
130
uintptr_t *result = (uintptr_t*)mcsNode->getSymbol()->castToStaticSymbol()->getStaticAddress();
131
heuristicTrace(inliner->tracer()," Success: isMutableCallSiteTargetInvokeExact(%p)=%p (fixed object reference)", callSite, result);
132
return result;
133
}
134
else
135
{
136
return failMCS("Unknown MutableCallSite object", callSite, inliner);
137
}
138
}
139
140
141
142
TR_CallSite* TR_CallSite::create(TR::TreeTop* callNodeTreeTop,
143
TR::Node *parent,
144
TR::Node* callNode,
145
TR_OpaqueClassBlock *receiverClass,
146
TR::SymbolReference *symRef,
147
TR_ResolvedMethod *resolvedMethod,
148
TR::Compilation* comp,
149
TR_Memory* trMemory,
150
TR_AllocationKind kind,
151
TR_ResolvedMethod* caller,
152
int32_t depth,
153
bool allConsts)
154
155
{
156
157
TR::MethodSymbol *calleeSymbol = symRef->getSymbol()->castToMethodSymbol();
158
TR_ResolvedMethod* lCaller = caller ? caller : symRef->getOwningMethod(comp);
159
160
if (callNode->getOpCode().isCallIndirect())
161
{
162
if (calleeSymbol->isInterface() )
163
{
164
return new (trMemory, kind) TR_J9InterfaceCallSite (lCaller,
165
callNodeTreeTop,
166
parent,
167
callNode,
168
calleeSymbol->getMethod(),
169
receiverClass,
170
(int32_t)symRef->getOffset(),
171
symRef->getCPIndex(),
172
resolvedMethod,
173
calleeSymbol->getResolvedMethodSymbol(),
174
callNode->getOpCode().isCallIndirect(),
175
calleeSymbol->isInterface(),
176
callNode->getByteCodeInfo(),
177
comp,
178
depth,
179
allConsts);
180
}
181
else
182
{
183
if (calleeSymbol->getResolvedMethodSymbol() &&
184
calleeSymbol->getResolvedMethodSymbol()->getResolvedMethod()->convertToMethod()->isArchetypeSpecimen() &&
185
calleeSymbol->getResolvedMethodSymbol()->getResolvedMethod()->getMethodHandleLocation())
186
{
187
return new (trMemory, kind) TR_J9MethodHandleCallSite (lCaller,
188
callNodeTreeTop,
189
parent,
190
callNode,
191
calleeSymbol->getMethod(),
192
receiverClass,
193
(int32_t)symRef->getOffset(),
194
symRef->getCPIndex(),
195
resolvedMethod,
196
calleeSymbol->getResolvedMethodSymbol(),
197
callNode->getOpCode().isCallIndirect(),
198
calleeSymbol->isInterface(),
199
callNode->getByteCodeInfo(),
200
comp,
201
depth,
202
allConsts) ;
203
}
204
205
if (calleeSymbol->getResolvedMethodSymbol() && calleeSymbol->getResolvedMethodSymbol()->getRecognizedMethod() == TR::java_lang_invoke_MethodHandle_invokeExact)
206
{
207
return new (trMemory, kind) TR_J9MutableCallSite (lCaller,
208
callNodeTreeTop,
209
parent,
210
callNode,
211
calleeSymbol->getMethod(),
212
receiverClass,
213
(int32_t)symRef->getOffset(),
214
symRef->getCPIndex(),
215
resolvedMethod,
216
calleeSymbol->getResolvedMethodSymbol(),
217
callNode->getOpCode().isCallIndirect(),
218
calleeSymbol->isInterface(),
219
callNode->getByteCodeInfo(),
220
comp,
221
depth,
222
allConsts) ;
223
}
224
225
return new (trMemory, kind) TR_J9VirtualCallSite (lCaller,
226
callNodeTreeTop,
227
parent,
228
callNode,
229
calleeSymbol->getMethod(),
230
receiverClass,
231
(int32_t)symRef->getOffset(),
232
symRef->getCPIndex(),
233
resolvedMethod,
234
calleeSymbol->getResolvedMethodSymbol(),
235
callNode->getOpCode().isCallIndirect(),
236
calleeSymbol->isInterface(),
237
callNode->getByteCodeInfo(),
238
comp,
239
depth,
240
allConsts) ;
241
242
}
243
}
244
245
return new (trMemory, kind) TR_DirectCallSite (lCaller,
246
callNodeTreeTop,
247
parent,
248
callNode,
249
calleeSymbol->getMethod(),
250
resolvedMethod && !resolvedMethod->isStatic() ? receiverClass : NULL,
251
(int32_t)symRef->getOffset(),
252
symRef->getCPIndex(),
253
resolvedMethod,
254
calleeSymbol->getResolvedMethodSymbol(),
255
callNode->getOpCode().isCallIndirect(),
256
calleeSymbol->isInterface(),
257
callNode->getByteCodeInfo(),
258
comp,
259
depth,
260
allConsts) ;
261
262
}
263
264
265
266
static void computeNumLivePendingSlotsAndNestingDepth(TR::Optimizer* optimizer, TR_CallTarget* calltarget, TR_CallStack* callStack, int32_t& numLivePendingPushSlots, int32_t& nestingDepth)
267
{
268
TR::Compilation *comp = optimizer->comp();
269
270
if (comp->getOption(TR_EnableOSR))
271
{
272
TR::Block *containingBlock = calltarget->_myCallSite->_callNodeTreeTop->getEnclosingBlock();
273
int32_t weight = 1;
274
nestingDepth = weight/10;
275
276
TR::Node *callNode = calltarget->_myCallSite->_callNode;
277
int32_t callerIndex = callNode->getByteCodeInfo().getCallerIndex();
278
TR::ResolvedMethodSymbol *caller = (callerIndex == -1) ? comp->getMethodSymbol()
279
: comp->getInlinedResolvedMethodSymbol(callerIndex);
280
TR_OSRMethodData *osrMethodData = comp->getOSRCompilationData()->findOrCreateOSRMethodData(callerIndex, caller);
281
TR_Array<List<TR::SymbolReference> > *pendingPushSymRefs = caller->getPendingPushSymRefs();
282
283
int32_t numPendingSlots = 0;
284
285
if (pendingPushSymRefs)
286
numPendingSlots = pendingPushSymRefs->size();
287
288
TR_BitVector *deadSymRefs = osrMethodData->getLiveRangeInfo(calltarget->_myCallSite->_callNode->getByteCodeIndex());
289
290
for (int32_t i=0;i<numPendingSlots;i++)
291
{
292
List<TR::SymbolReference> symRefsAtThisSlot = (*pendingPushSymRefs)[i];
293
294
if (symRefsAtThisSlot.isEmpty()) continue;
295
296
ListIterator<TR::SymbolReference> symRefsIt(&symRefsAtThisSlot);
297
TR::SymbolReference *nextSymRef;
298
for (nextSymRef = symRefsIt.getCurrent(); nextSymRef; nextSymRef=symRefsIt.getNext())
299
{
300
if (!deadSymRefs || !deadSymRefs->get(nextSymRef->getReferenceNumber()))
301
numLivePendingPushSlots++;
302
}
303
}
304
305
optimizer->comp()->incNumLivePendingPushSlots(numLivePendingPushSlots);
306
optimizer->comp()->incNumLoopNestingLevels(nestingDepth);
307
}
308
}
309
310
/*
311
* Populate the OSRCallSiteRematTable using the pending push stores before this call.
312
* To achieve this, RematTools is applied to the pending pushes that correspond to the call,
313
* however, it is limited to using autos, parms and pending push temps as others may be
314
* modified within the call.
315
*/
316
static void populateOSRCallSiteRematTable(TR::Optimizer* optimizer, TR_CallTarget* calltarget,
317
TR_CallStack* callStack)
318
{
319
static const char *verboseCallSiteRemat = feGetEnv("TR_VerboseOSRCallSiteRemat");
320
TR::TreeTop *call = calltarget->_myCallSite->_callNodeTreeTop;
321
TR::ResolvedMethodSymbol *method = callStack->_methodSymbol;
322
TR::Compilation *comp = optimizer->comp();
323
TR_ByteCodeInfo &bci = method->getOSRByteCodeInfo(call->getNode());
324
TR::TreeTop *blockStart = call->getEnclosingBlock()->getFirstRealTreeTop();
325
326
TR::SparseBitVector scanTargets(comp->allocator());
327
RematSafetyInformation safetyInfo(comp);
328
TR::list<TR::TreeTop *> failedPP(getTypedAllocator<TR::TreeTop*>(comp->allocator()));
329
330
// Search through all of the PPS for those that can be remated
331
//
332
for (
333
TR::TreeTop *cursor = call->getPrevTreeTop();
334
cursor && method->isOSRRelatedNode(cursor->getNode(), bci);
335
cursor = cursor->getPrevTreeTop())
336
{
337
TR::Node *store = cursor->getNode();
338
if (!store->getOpCode().isStoreDirect() || !store->getSymbol()->isPendingPush())
339
continue;
340
341
TR::Node *child = store->getFirstChild();
342
// A PPS of an auto/parm. Necessary to scan to check if auto/parm has not been modified
343
// since it was anchored.
344
//
345
int32_t callerIndex = child->getByteCodeInfo().getCallerIndex();
346
347
if (child->getOpCode().hasSymbolReference()
348
&& (child->getSymbol()->isParm()
349
|| (child->getSymbol()->isAuto()
350
&& child->getSymbolReference()->getCPIndex() <
351
(( (callerIndex == -1) ? comp->getMethodSymbol()
352
: comp->getInlinedResolvedMethodSymbol(callerIndex) )->getFirstJitTempIndex()))))
353
{
354
if (comp->trace(OMR::inlining))
355
traceMsg(comp, "callSiteRemat: found potential pending push #%d with store #%d\n", store->getSymbolReference()->getReferenceNumber(),
356
child->getSymbolReference()->getReferenceNumber());
357
358
TR::SparseBitVector symRefsToCheck(comp->allocator());
359
symRefsToCheck[child->getSymbolReference()->getReferenceNumber()] = true;
360
scanTargets[child->getGlobalIndex()] = true;
361
safetyInfo.add(cursor, symRefsToCheck);
362
}
363
364
// Storing failures, will search for a double store that occurs before
365
//
366
else
367
{
368
if (comp->trace(OMR::inlining))
369
traceMsg(comp, "callSiteRemat: failed to find store for pending push #%d\n", store->getSymbolReference()->getReferenceNumber());
370
371
failedPP.push_back(cursor);
372
}
373
}
374
375
// Perform search for any double stores
376
// This goes from the start of the block to the call, as PPs may store
377
// duplicate values
378
//
379
if (failedPP.size() > 0)
380
RematTools::walkTreeTopsCalculatingRematFailureAlternatives(comp,
381
blockStart, call, failedPP, scanTargets, safetyInfo, verboseCallSiteRemat != NULL);
382
383
// Perform the safety check, to ensure symrefs haven't been
384
// modified.
385
//
386
TR::SparseBitVector unsafeSymRefs(comp->allocator());
387
if (!scanTargets.IsZero())
388
RematTools::walkTreesCalculatingRematSafety(comp, blockStart,
389
call, scanTargets, unsafeSymRefs, verboseCallSiteRemat != NULL);
390
391
// Perform place those without unsafe symrefs in the remat table
392
//
393
for (uint32_t i = 0; i < safetyInfo.size(); ++i)
394
{
395
TR::TreeTop *storeTree = safetyInfo.argStore(i);
396
TR::TreeTop *rematTree = safetyInfo.rematTreeTop(i);
397
TR::Node *node = rematTree->getNode();
398
TR::Node *child = node->getFirstChild();
399
400
if (!unsafeSymRefs.Intersects(safetyInfo.symRefDependencies(i)))
401
{
402
if (storeTree == rematTree)
403
{
404
if (comp->trace(OMR::inlining))
405
traceMsg(comp, "callSiteRemat: adding pending push #%d with store #%d to remat table\n",
406
storeTree->getNode()->getSymbolReference()->getReferenceNumber(),
407
child->getSymbolReference()->getReferenceNumber());
408
409
comp->setOSRCallSiteRemat(comp->getCurrentInlinedSiteIndex(),
410
storeTree->getNode()->getSymbolReference(),
411
child->getSymbolReference());
412
}
413
else
414
{
415
int32_t callerIndex = node->getByteCodeInfo().getCallerIndex();
416
if (node->getSymbol()->isParm()
417
|| node->getSymbol()->isPendingPush()
418
|| (node->getSymbol()->isAuto()
419
&& node->getSymbolReference()->getCPIndex() <
420
(( (callerIndex == -1) ? comp->getMethodSymbol()
421
: comp->getInlinedResolvedMethodSymbol(callerIndex) )->getFirstJitTempIndex())))
422
{
423
if (comp->trace(OMR::inlining))
424
traceMsg(comp, "callSiteRemat: adding pending push #%d with store #%d to remat table\n",
425
storeTree->getNode()->getSymbolReference()->getReferenceNumber(),
426
node->getSymbolReference()->getReferenceNumber());
427
428
comp->setOSRCallSiteRemat(comp->getCurrentInlinedSiteIndex(),
429
storeTree->getNode()->getSymbolReference(),
430
node->getSymbolReference());
431
}
432
}
433
}
434
}
435
}
436
437
bool TR_InlinerBase::inlineCallTarget(TR_CallStack *callStack, TR_CallTarget *calltarget, bool inlinefromgraph, TR_PrexArgInfo *argInfo, TR::TreeTop** cursorTreeTop)
438
{
439
440
TR_InlinerDelimiter delimiter(tracer(),"TR_InlinerBase::inlineCallTarget");
441
442
char *sig = "multiLeafArrayCopy";
443
if (strncmp(calltarget->_calleeMethod->nameChars(), sig, strlen(sig)) == 0)
444
{
445
_nodeCountThreshold = 8192;
446
heuristicTrace(tracer(),"Setting _nodeCountThreshold to %d for multiLeafArrayCopy",_nodeCountThreshold);
447
}
448
449
if (!((TR_J9InlinerPolicy* )getPolicy())->doCorrectnessAndSizeChecksForInlineCallTarget(callStack, calltarget, inlinefromgraph, argInfo))
450
{
451
//@TODO do we need to undo _nodeCountThreshold???!
452
return false;
453
}
454
455
// Last chance to improve our prex info
456
//
457
if (!calltarget->_prexArgInfo)
458
calltarget->_prexArgInfo = getUtil()->computePrexInfo(calltarget);
459
460
argInfo = TR_PrexArgInfo::enhance(calltarget->_prexArgInfo, argInfo, comp());
461
calltarget->_prexArgInfo = argInfo;
462
bool tracePrex = comp()->trace(OMR::inlining) || comp()->trace(OMR::invariantArgumentPreexistence);
463
if (tracePrex && argInfo)
464
{
465
traceMsg(comp(), "Final prex argInfo:\n");
466
argInfo->dumpTrace();
467
}
468
469
if (!comp()->incInlineDepth(calltarget->_calleeSymbol,
470
calltarget->_myCallSite->_callNode,
471
!calltarget->_myCallSite->_isIndirectCall,
472
calltarget->_guard,
473
calltarget->_receiverClass,
474
argInfo))
475
{
476
return false;
477
}
478
479
//OSR
480
int32_t numLivePendingPushSlots = 0;
481
int32_t nestingDepth = 0;
482
if (comp()->getOption(TR_EnableOSR))
483
{
484
computeNumLivePendingSlotsAndNestingDepth(_optimizer, calltarget, callStack, numLivePendingPushSlots, nestingDepth);
485
}
486
487
// Add the pending pushes above this call to the OSRCallSiteRematTable
488
if (comp()->getOption(TR_EnableOSR)
489
&& !comp()->getOption(TR_DisableOSRCallSiteRemat)
490
&& comp()->getOSRMode() == TR::voluntaryOSR
491
&& comp()->isOSRTransitionTarget(TR::postExecutionOSR)
492
&& comp()->isPotentialOSRPointWithSupport(calltarget->_myCallSite->_callNodeTreeTop)
493
&& performTransformation(comp(), "O^O CALL SITE REMAT: populate OSR call site remat table for call [%p]\n", calltarget->_myCallSite->_callNode))
494
{
495
if (comp()->trace(OMR::inlining))
496
traceMsg(comp(), "callSiteRemat: populating OSR call site remat table for call [%p]\n", calltarget->_myCallSite->_callNode);
497
populateOSRCallSiteRematTable(_optimizer, calltarget, callStack);
498
}
499
500
bool successful = inlineCallTarget2(callStack, calltarget, cursorTreeTop, inlinefromgraph, 99);
501
502
// if inlining fails, we need to tell decInlineDepth to remove elements that
503
// we added during inlineCallTarget2
504
comp()->decInlineDepth(!successful);
505
506
if (comp()->getOption(TR_EnableOSR))
507
{
508
comp()->incNumLivePendingPushSlots(-numLivePendingPushSlots);
509
comp()->incNumLoopNestingLevels(-nestingDepth);
510
}
511
512
if (NumInlinedMethods != NULL)
513
{
514
NumInlinedMethods[comp()->getMethodHotness()]++;
515
InlinedSizes[comp()->getMethodHotness()] += TR::Compiler->mtd.bytecodeSize(calltarget->_calleeSymbol->getResolvedMethod()->getPersistentIdentifier());
516
}
517
return successful;
518
}
519
520
TR_ResolvedMethod* TR_J9VirtualCallSite::findSingleJittedImplementer (TR_InlinerBase *inliner)
521
{
522
return comp()->getPersistentInfo()->getPersistentCHTable()->findSingleJittedImplementer(_receiverClass,TR::Compiler->cls.isInterfaceClass(comp(), _receiverClass) ? _cpIndex : _vftSlot,_callerResolvedMethod, comp(), _initialCalleeSymbol);
523
}
524
525
bool TR_J9VirtualCallSite::findCallSiteForAbstractClass(TR_InlinerBase* inliner)
526
{
527
TR_PersistentCHTable *chTable = comp()->getPersistentInfo()->getPersistentCHTable();
528
TR_ResolvedMethod *implementer;
529
530
bool canInline = (!comp()->compileRelocatableCode() || comp()->getOption(TR_UseSymbolValidationManager));
531
if (canInline && TR::Compiler->cls.isAbstractClass(comp(), _receiverClass) &&!comp()->getOption(TR_DisableAbstractInlining) &&
532
(implementer = chTable->findSingleAbstractImplementer(_receiverClass, _vftSlot, _callerResolvedMethod, comp())))
533
{
534
heuristicTrace(inliner->tracer(),"Found a single Abstract Implementer %p, signature = %s",implementer,inliner->tracer()->traceSignature(implementer));
535
TR_VirtualGuardSelection *guard = new (comp()->trHeapMemory()) TR_VirtualGuardSelection(TR_AbstractGuard, TR_MethodTest);
536
addTarget(comp()->trMemory(),inliner,guard,implementer,_receiverClass,heapAlloc);
537
return true;
538
}
539
540
return false;
541
}
542
543
TR_OpaqueClassBlock* TR_J9VirtualCallSite::getClassFromMethod ()
544
{
545
return _initialCalleeMethod->classOfMethod();
546
}
547
548
// Ensure the call site is a basic invokevirtual; the bytecode is an 'invokevirtaul' and the
549
// cpIndex is the same as the call site _cpIndex. This will insure that the call site is not
550
// some type of transformed call site that may not be a valid case for allowing an isInstanceOf()
551
// call during AOT compiles
552
bool TR_J9VirtualCallSite::isBasicInvokeVirtual()
553
{
554
TR_OpaqueMethodBlock *method = ((TR_ResolvedJ9Method*)_initialCalleeMethod->owningMethod())->getPersistentIdentifier();
555
int32_t methodSize = TR::Compiler->mtd.bytecodeSize(method);
556
uintptr_t methodStart = TR::Compiler->mtd.bytecodeStart(method);
557
558
TR_ASSERT_FATAL(_bcInfo.getByteCodeIndex() >= 0 && _bcInfo.getByteCodeIndex()+2 < methodSize, "Bytecode index can't be less than zero or higher than the methodSize");
559
560
uint8_t *pc = (uint8_t *)(methodStart + _bcInfo.getByteCodeIndex());
561
TR_J9ByteCode bytecode = TR_J9ByteCodeIterator::convertOpCodeToByteCodeEnum(*pc);
562
//fprintf( stderr, "method %p, size %d, start %p, PC %p, BC: %d==%d? (%d)\n", method, methodSize, methodStart, pc, bytecode, J9BCinvokevirtual, (bytecode==J9BCinvokevirtual));
563
if (bytecode==J9BCinvokevirtual)
564
{
565
uint16_t cpIndex = *(uint16_t*)(pc + 1);
566
//fprintf( stderr, "BC cpIndex %d, callSite cpIndex %d\n", cpIndex, _cpIndex );
567
if (_cpIndex==cpIndex)
568
{
569
return true;
570
}
571
}
572
return false;
573
}
574
575
bool TR_J9VirtualCallSite::findCallSiteTarget(TR_CallStack *callStack, TR_InlinerBase* inliner)
576
{
577
if (hasFixedTypeArgInfo())
578
{
579
bool result = findCallTargetUsingArgumentPreexistence(inliner);
580
if (!result) //findCallTargetUsingArgumentPreexistence couldn't reconcile class types
581
{
582
heuristicTrace(inliner->tracer(), "Don't inline anything at the risk of inlining dead code");
583
return false;
584
}
585
586
if (numTargets()) //findCallTargetUsingArgumentPreexistence added a target
587
{
588
return true;
589
}
590
591
//findCallTargetUsingArgumentPreexistence couldn't use argInfo
592
//Clear _ecsPrexArgInfo so it isn't propagated down to callees of this callsite
593
//And try other techniques
594
_ecsPrexArgInfo->set(0, NULL);
595
}
596
597
tryToRefineReceiverClassBasedOnResolvedTypeArgInfo(inliner);
598
599
// Refine receiver class based on CP class
600
// When we have an invokevirtual on an abstract method defined in an interface class,
601
// the call site's class will be more concrete than class of method.
602
// This happens when an abstract class implements an interface class without providing
603
// implementation for the given method, and the call site is refering to the method of
604
// the abstract class, the cp entry of the method ref will be resolved to j9method of
605
// the interface class. However, the class ref from cp will be resolved to the abstract
606
// class, which is more concrete
607
//
608
if (_cpIndex != -1 && _receiverClass && TR::Compiler->cls.isInterfaceClass(comp(), _receiverClass) && isBasicInvokeVirtual())
609
{
610
TR_ResolvedMethod* owningMethod = _initialCalleeMethod->owningMethod();
611
TR_ResolvedJ9Method* j9OwningMethod = (TR_ResolvedJ9Method*)owningMethod;
612
int32_t nameLen=0, sigLen=0;
613
char *cpMethodName = j9OwningMethod->getMethodNameFromConstantPool(_cpIndex, nameLen);
614
char *cpMethodSig = j9OwningMethod->getMethodSignatureFromConstantPool(_cpIndex, sigLen);
615
char *methodName = _initialCalleeMethod->nameChars();
616
char *methodSig = _initialCalleeMethod->signatureChars();
617
if (nameLen && nameLen == _initialCalleeMethod->nameLength() && sigLen && sigLen == _initialCalleeMethod->signatureLength() &&
618
strncmp(cpMethodName, methodName, nameLen)==0 && strncmp(cpMethodSig, methodSig, sigLen)==0)
619
{
620
int32_t classRefCPIndex = owningMethod->classCPIndexOfMethod(_cpIndex);
621
TR_OpaqueClassBlock* callSiteClass = owningMethod->getClassFromConstantPool(comp(), classRefCPIndex, true);
622
if (callSiteClass && callSiteClass != _receiverClass)
623
{
624
if (comp()->fej9()->isJavaLangObject(callSiteClass))
625
_isCallingObjectMethod = TR_yes;
626
else
627
{
628
TR_ASSERT_FATAL(fe()->isInstanceOf(callSiteClass, _receiverClass, true, true, true) == TR_yes , "CallSiteClass is incompatible with the receiverClass.");
629
_isCallingObjectMethod = TR_no;
630
if (comp()->trace(OMR::inlining))
631
{
632
char* oldClassSig = TR::Compiler->cls.classSignature(comp(), _receiverClass, comp()->trMemory());
633
char* callSiteClassSig = TR::Compiler->cls.classSignature(comp(), callSiteClass, comp()->trMemory());
634
traceMsg(comp(), "Receiver type %p sig %s is class of an interface method for invokevirtual, improve it to call site receiver type %p sig %s\n", _receiverClass, oldClassSig, callSiteClass, callSiteClassSig);
635
}
636
// Update receiver class
637
_receiverClass = callSiteClass;
638
}
639
}
640
}
641
}
642
643
if (addTargetIfMethodIsNotOverriden(inliner) ||
644
addTargetIfMethodIsNotOverridenInReceiversHierarchy(inliner) ||
645
findCallSiteForAbstractClass(inliner) ||
646
addTargetIfThereIsSingleImplementer(inliner))
647
{
648
return true;
649
}
650
651
return findProfiledCallTargets(callStack, inliner);
652
}
653
654
/*
655
static TR_ResolvedMethod * findSingleImplementer(
656
TR_OpaqueClassBlock * thisClass, int32_t cpIndexOrVftSlot, TR_ResolvedMethod * callerMethod, TR::Compilation * comp, bool locked, TR_YesNoMaybe useGetResolvedInterfaceMethod)
657
{
658
if (comp->getOption(TR_DisableCHOpts))
659
return 0;
660
661
662
663
TR_PersistentClassInfo * classInfo = comp->getPersistentInfo()->getPersistentCHTable()->findClassInfoAfterLocking(thisClass, comp, true);
664
if (!classInfo)
665
{
666
return 0;
667
}
668
669
TR_ResolvedMethod *implArray[2]; // collect maximum 2 implementers if you can
670
int32_t implCount = TR_ClassQueries::collectImplementorsCapped(classInfo, implArray, 2, cpIndexOrVftSlot, callerMethod, comp, locked, useGetResolvedInterfaceMethod);
671
return (implCount == 1 ? implArray[0] : 0);
672
}
673
*/
674
675
bool TR_J9InterfaceCallSite::findCallSiteTarget (TR_CallStack *callStack, TR_InlinerBase* inliner)
676
{
677
static char *minimizedInlineJIT = feGetEnv("TR_JITInlineMinimized");
678
679
if (minimizedInlineJIT)
680
return false;
681
682
if (hasFixedTypeArgInfo())
683
{
684
bool result = findCallTargetUsingArgumentPreexistence(inliner);
685
if (!result) //findCallTargetUsingArgumentPreexistence couldn't reconcile class types
686
{
687
heuristicTrace(inliner->tracer(), "Don't inline anything at the risk of inlining dead code");
688
return false;
689
}
690
691
if (numTargets()) //findCallTargetUsingArgumentPreexistence added a target
692
{
693
return true;
694
}
695
696
//findCallTargetUsingArgumentPreexistence couldn't use argInfo
697
//Clear _ecsPrexArgInfo so it wont be propagated down to callees of this callsite
698
//And try other techniques
699
_ecsPrexArgInfo->set(0, NULL);
700
}
701
702
if (!_receiverClass)
703
{
704
int32_t len = _interfaceMethod->classNameLength();
705
char * s = TR::Compiler->cls.classNameToSignature(_interfaceMethod->classNameChars(), len, comp());
706
_receiverClass = comp()->fej9()->getClassFromSignature(s, len, _callerResolvedMethod, true);
707
}
708
709
//TR_OpaqueClassBlock* _receiverClass = NULL;
710
tryToRefineReceiverClassBasedOnResolvedTypeArgInfo(inliner);
711
712
//TR_ResolvedMethod* calleeResolvedMethod = inliner->findInterfaceImplementationToInline(_interfaceMethod, _cpIndex, _callerResolvedMethod, _receiverClass);
713
TR_ResolvedMethod* calleeResolvedMethod = comp()->getPersistentInfo()->getPersistentCHTable()->findSingleImplementer(_receiverClass, _cpIndex, _callerResolvedMethod, inliner->comp(), false, TR_yes);
714
715
if (!comp()->performVirtualGuardNOPing() || (comp()->compileRelocatableCode() && !TR::Options::getCmdLineOptions()->allowRecompilation()))
716
{
717
calleeResolvedMethod = NULL;
718
}
719
720
heuristicTrace(inliner->tracer(), "Found a Single Interface Implementer with Resolved Method %p for callsite %p",calleeResolvedMethod,this);
721
722
if (calleeResolvedMethod && !calleeResolvedMethod->virtualMethodIsOverridden())
723
{
724
TR_VirtualGuardSelection * guard = new (comp()->trHeapMemory()) TR_VirtualGuardSelection(TR_InterfaceGuard, TR_MethodTest);
725
addTarget(comp()->trMemory(),inliner,guard,calleeResolvedMethod,_receiverClass,heapAlloc);
726
heuristicTrace(inliner->tracer(),"Call is an Interface with a Single Implementer guard %p\n", guard);
727
return true;
728
}
729
730
return findProfiledCallTargets(callStack, inliner);
731
}
732
733
TR_OpaqueClassBlock* TR_J9InterfaceCallSite::getClassFromMethod ()
734
{
735
int32_t len = _interfaceMethod->classNameLength();
736
char * s = TR::Compiler->cls.classNameToSignature(_interfaceMethod->classNameChars(), len, comp());
737
return comp()->fej9()->getClassFromSignature(s, len, _callerResolvedMethod, true);
738
}
739
740
TR_ResolvedMethod* TR_J9InterfaceCallSite::getResolvedMethod (TR_OpaqueClassBlock* klass)
741
{
742
return _callerResolvedMethod->getResolvedInterfaceMethod(comp(), klass , _cpIndex);
743
}
744
745
void TR_J9InterfaceCallSite::findSingleProfiledMethod(ListIterator<TR_ExtraAddressInfo>& sortedValuesIt, TR_AddressInfo * valueInfo, TR_InlinerBase* inliner)
746
{
747
return;
748
}
749
750
bool TR_J9MethodHandleCallSite::findCallSiteTarget (TR_CallStack *callStack, TR_InlinerBase* inliner)
751
{
752
heuristicTrace(inliner->tracer(),"Call is MethodHandle thunk call.");
753
addTarget(comp()->trMemory(), inliner,
754
new (comp()->trHeapMemory()) TR_VirtualGuardSelection(TR_NoGuard),
755
_initialCalleeMethod,
756
_receiverClass, heapAlloc);
757
758
return true;
759
}
760
761
bool TR_J9MutableCallSite::findCallSiteTarget (TR_CallStack *callStack, TR_InlinerBase* inliner)
762
{
763
if (!_mcsReferenceLocation)
764
_mcsReferenceLocation = isMutableCallSiteTargetInvokeExact(this, inliner); // JSR292: Looking for calls through MutableCallSite
765
if (_mcsReferenceLocation)
766
{
767
// TODO:JSR292: This belongs behind the FE interface
768
heuristicTrace(inliner->tracer(),"Call is MutableCallSite.target.invokeExact call.");
769
if (!comp()->performVirtualGuardNOPing())
770
{
771
heuristicTrace(inliner->tracer()," Virtual guard NOPing disabled");
772
return false;
773
}
774
TR_VirtualGuardSelection *vgs = new (comp()->trHeapMemory()) TR_VirtualGuardSelection(TR_MutableCallSiteTargetGuard, TR_DummyTest);
775
vgs->_mutableCallSiteObject = _mcsReferenceLocation;
776
TR::KnownObjectTable *knot = comp()->getOrCreateKnownObjectTable();
777
778
#if defined(J9VM_OPT_JITSERVER)
779
if (comp()->isOutOfProcessCompilation())
780
{
781
vgs->_mutableCallSiteEpoch = TR::KnownObjectTable::UNKNOWN;
782
bool knotEnabled = (knot != NULL);
783
auto stream = TR::CompilationInfo::getStream();
784
stream->write(JITServer::MessageType::KnownObjectTable_mutableCallSiteEpoch, _mcsReferenceLocation, knotEnabled);
785
786
auto recv = stream->read<uintptr_t, TR::KnownObjectTable::Index, uintptr_t*>();
787
uintptr_t mcsObject = std::get<0>(recv);
788
TR::KnownObjectTable::Index knotIndex = std::get<1>(recv);
789
uintptr_t *objectPointerReference = std::get<2>(recv);
790
791
if (mcsObject && knot && (knotIndex != TR::KnownObjectTable::UNKNOWN))
792
{
793
vgs->_mutableCallSiteEpoch = knotIndex;
794
knot->updateKnownObjectTableAtServer(knotIndex, objectPointerReference);
795
}
796
else
797
{
798
vgs->_mutableCallSiteObject = NULL;
799
}
800
}
801
else
802
#endif /* defined(J9VM_OPT_JITSERVER) */
803
{
804
TR::VMAccessCriticalSection mutableCallSiteEpoch(comp()->fej9());
805
vgs->_mutableCallSiteEpoch = TR::KnownObjectTable::UNKNOWN;
806
uintptr_t mcsObject = comp()->fej9()->getStaticReferenceFieldAtAddress((uintptr_t)_mcsReferenceLocation);
807
if (mcsObject && knot)
808
{
809
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp()->fej9());
810
vgs->_mutableCallSiteEpoch = fej9->mutableCallSiteEpoch(comp(), mcsObject);
811
}
812
else
813
{
814
vgs->_mutableCallSiteObject = NULL;
815
}
816
}
817
818
if (vgs->_mutableCallSiteEpoch != TR::KnownObjectTable::UNKNOWN)
819
{
820
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
821
TR::MethodSymbol::Kinds methodKind = TR::MethodSymbol::Static;
822
TR_OpaqueMethodBlock *targetJ9Method =
823
comp()->fej9()->targetMethodFromMethodHandle(comp(), vgs->_mutableCallSiteEpoch);
824
825
TR_ASSERT_FATAL(
826
targetJ9Method != NULL,
827
"failed to find MCS target (obj%d) LambdaForm method",
828
(int)vgs->_mutableCallSiteEpoch);
829
830
TR_ResolvedMethod *targetMethod = comp()->fej9()->createResolvedMethod(
831
comp()->trMemory(), targetJ9Method, callStack->_method);
832
833
heuristicTrace(
834
inliner->tracer(),
835
"Refine callee of MCS target invokeBasic to %s\n",
836
targetMethod->signature(comp()->trMemory(), stackAlloc));
837
#else
838
TR::MethodSymbol::Kinds methodKind = TR::MethodSymbol::ComputedVirtual;
839
TR_ResolvedMethod *targetMethod = comp()->fej9()->createMethodHandleArchetypeSpecimen(
840
comp()->trMemory(),
841
knot->getPointerLocation(vgs->_mutableCallSiteEpoch),
842
_callerResolvedMethod);
843
#endif
844
TR_CallTarget *target = addTarget(comp()->trMemory(), inliner, vgs,
845
targetMethod, _receiverClass, heapAlloc);
846
TR_ASSERT(target , "There should be only one target for TR_MutableCallSite");
847
target->_calleeMethodKind = methodKind;
848
849
heuristicTrace(
850
inliner->tracer(),
851
" addTarget: MutableCallSite %p epoch is obj%d",
852
vgs->_mutableCallSiteObject,
853
vgs->_mutableCallSiteEpoch);
854
855
return true;
856
}
857
else if (vgs->_mutableCallSiteObject)
858
{
859
heuristicTrace(inliner->tracer()," MutableCallSite.epoch is currently NULL. Can't devirtualize.");
860
}
861
else
862
{
863
heuristicTrace(inliner->tracer()," MutableCallSite is NULL! That is rather unexpected.");
864
}
865
return false;
866
}
867
868
return false;
869
}
870
871
bool TR_InlinerBase::tryToGenerateILForMethod (TR::ResolvedMethodSymbol* calleeSymbol, TR::ResolvedMethodSymbol* callerSymbol, TR_CallTarget* calltarget)
872
{
873
TR_J9InlinerPolicy *j9inlinerPolicy = (TR_J9InlinerPolicy *) getPolicy();
874
return j9inlinerPolicy->_tryToGenerateILForMethod (calleeSymbol, callerSymbol, calltarget);
875
}
876
877
void TR_InlinerBase::getBorderFrequencies(int32_t &hotBorderFrequency, int32_t &coldBorderFrequency, TR_ResolvedMethod * calleeResolvedMethod, TR::Node *callNode)
878
{
879
if (comp()->getMethodHotness() > warm)
880
{
881
hotBorderFrequency = comp()->isServerInlining() ? 2000 : 2500;
882
coldBorderFrequency = 0;
883
}
884
else if (!comp()->getOption(TR_DisableConservativeInlining) &&
885
calleeResolvedMethod->maxBytecodeIndex() >= comp()->getOptions()->getAlwaysWorthInliningThreshold() &&
886
!alwaysWorthInlining(calleeResolvedMethod, callNode))
887
{
888
hotBorderFrequency = 6000;
889
coldBorderFrequency = 1500;
890
}
891
else // old days
892
{
893
if (comp()->isServerInlining())
894
{
895
hotBorderFrequency = 2000;
896
coldBorderFrequency = 50;
897
}
898
else
899
{
900
hotBorderFrequency = 2500;
901
coldBorderFrequency = 1000;
902
}
903
}
904
905
// Did the user specify specific values? If so, use those
906
if (comp()->getOptions()->getInlinerBorderFrequency() >= 0)
907
hotBorderFrequency = comp()->getOptions()->getInlinerBorderFrequency();
908
//if (comp()->getOptions()->getInlinerColdBorderFrequency() >= 0)
909
// coldBorderFrequency = comp()->getOptions()->getInlinerColdBorderFrequency();
910
if (comp()->getOptions()->getInlinerVeryColdBorderFrequency() >= 0)
911
coldBorderFrequency = comp()->getOptions()->getInlinerVeryColdBorderFrequency();
912
913
914
915
return;
916
}
917
918
919
int TR_InlinerBase::checkInlineableWithoutInitialCalleeSymbol (TR_CallSite* callsite, TR::Compilation* comp)
920
{
921
if (!callsite->_isInterface)
922
{
923
return Unresolved_Callee;
924
}
925
926
return InlineableTarget;
927
}
928
929
930
int32_t TR_InlinerBase::scaleSizeBasedOnBlockFrequency(int32_t bytecodeSize, int32_t frequency, int32_t borderFrequency, TR_ResolvedMethod * calleeResolvedMethod, TR::Node *callNode, int32_t coldBorderFrequency)
931
{
932
int32_t maxFrequency = MAX_BLOCK_COUNT + MAX_COLD_BLOCK_COUNT;
933
if (frequency > borderFrequency)
934
{
935
float factor = (float)(maxFrequency - frequency) / (float)maxFrequency;
936
factor = std::max(factor, 0.7f);
937
938
939
bytecodeSize = (int32_t)((float)bytecodeSize * factor);
940
if (bytecodeSize < 10) bytecodeSize = 10;
941
}
942
else if (frequency < coldBorderFrequency &&
943
!alwaysWorthInlining(calleeResolvedMethod, callNode))
944
{
945
946
float factor = (float)frequency / (float)maxFrequency;
947
bytecodeSize = (int32_t)((float)bytecodeSize / (factor*factor));
948
}
949
950
return bytecodeSize;
951
952
}
953
954
float TR_MultipleCallTargetInliner::getScalingFactor(float factor)
955
{
956
return std::max(factor, 0.7f);
957
}
958
959
960
void TR_ProfileableCallSite::findSingleProfiledReceiver(ListIterator<TR_ExtraAddressInfo>& sortedValuesIt, TR_AddressInfo * valueInfo, TR_InlinerBase* inliner)
961
{
962
963
bool firstInstanceOfCheckFailed = false;
964
int32_t totalFrequency = valueInfo->getTotalFrequency();
965
966
967
for (TR_ExtraAddressInfo *profiledInfo = sortedValuesIt.getFirst(); profiledInfo != NULL; profiledInfo = sortedValuesIt.getNext())
968
{
969
int32_t freq = profiledInfo->_frequency;
970
TR_OpaqueClassBlock* tempreceiverClass = (TR_OpaqueClassBlock *) profiledInfo->_value;
971
972
float val = (float)freq/(float)valueInfo->getTotalFrequency(); //x87 hardware rounds differently if you leave this division in compare
973
974
975
bool preferMethodTest = false;
976
977
bool isClassObsolete = comp()->getPersistentInfo()->isObsoleteClass((void*)tempreceiverClass, comp()->fe());
978
979
if (!isClassObsolete)
980
{
981
int32_t len = 1;
982
const char *className = TR::Compiler->cls.classNameChars(comp(), tempreceiverClass, len);
983
984
if (!strncmp(className, "java/lang/ThreadLocal", 21) && !isInterface())
985
{
986
preferMethodTest = true;
987
}
988
// high opt level compiles during JIT STARTUP could be affected by classes being loaded - maximize the chances
989
// of success by using method tests
990
else if (comp()->getPersistentInfo()->getJitState() == STARTUP_STATE && comp()->getMethodHotness() >= hot)
991
{
992
preferMethodTest = true;
993
}
994
}
995
996
997
static const char* userMinProfiledCallFreq = feGetEnv("TR_MinProfiledCallFrequency");
998
static const float minProfiledCallFrequency = userMinProfiledCallFreq ? atof (userMinProfiledCallFreq) :
999
comp()->getOption(TR_DisableMultiTargetInlining) ? MIN_PROFILED_CALL_FREQUENCY : .10f;
1000
1001
if ((val >= minProfiledCallFrequency ||
1002
(firstInstanceOfCheckFailed && val >= SECOND_BEST_MIN_CALL_FREQUENCY)) &&
1003
!comp()->getPersistentInfo()->isObsoleteClass((void*)tempreceiverClass, comp()->fe()))
1004
{
1005
TR_OpaqueClassBlock* callSiteClass = _receiverClass ? _receiverClass : getClassFromMethod();
1006
1007
if (callSiteClass && !isInterface() && TR::Compiler->cls.isInterfaceClass(comp(), callSiteClass) && isCallingObjectMethod() != TR_yes)
1008
{
1009
// TR_J9VirtualCallSite::findCallSiteTarget() should have refined the _receiverClass, but it must have failed, we need to abort this inlining
1010
if (comp()->trace(OMR::inlining))
1011
traceMsg(comp(), "inliner: callSiteClass [%p] is an interface making it impossible to confirm correct context of the profiled class [%p]\n", callSiteClass, tempreceiverClass);
1012
callSiteClass = 0;
1013
}
1014
1015
bool profiledClassIsNotInstanceOfCallSiteClass = true;
1016
if (callSiteClass)
1017
{
1018
comp()->enterHeuristicRegion();
1019
profiledClassIsNotInstanceOfCallSiteClass = (fe()->isInstanceOf(tempreceiverClass, callSiteClass, true, true, true) != TR_yes);
1020
comp()->exitHeuristicRegion();
1021
}
1022
1023
if (profiledClassIsNotInstanceOfCallSiteClass)
1024
{
1025
inliner->tracer()->insertCounter(Not_Sane,_callNodeTreeTop);
1026
firstInstanceOfCheckFailed = true;
1027
1028
if (comp()->trace(OMR::inlining))
1029
traceMsg(comp(), "inliner: profiled class [%p] is not instanceof callSiteClass [%p]\n", tempreceiverClass, callSiteClass);
1030
1031
continue;
1032
}
1033
1034
comp()->enterHeuristicRegion();
1035
TR_ResolvedMethod* targetMethod = getResolvedMethod (tempreceiverClass);
1036
comp()->exitHeuristicRegion();
1037
1038
if (!targetMethod)
1039
{
1040
continue;
1041
}
1042
1043
//origMethod
1044
1045
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp()->fe());
1046
// need to be able to store class chains for these methods
1047
if (comp()->compileRelocatableCode())
1048
{
1049
if (tempreceiverClass && comp()->getOption(TR_UseSymbolValidationManager))
1050
{
1051
if (!comp()->getSymbolValidationManager()->addProfiledClassRecord(tempreceiverClass))
1052
continue;
1053
/* call getResolvedMethod again to generate the validation records */
1054
TR_ResolvedMethod* target_method = getResolvedMethod (tempreceiverClass);
1055
1056
/* it is possible for getResolvedMethod to return NULL, since there might be
1057
* a problem when generating validation records
1058
*/
1059
if (!target_method)
1060
continue;
1061
1062
TR_OpaqueClassBlock *classOfMethod = target_method->classOfMethod();
1063
SVM_ASSERT_ALREADY_VALIDATED(comp()->getSymbolValidationManager(), classOfMethod);
1064
}
1065
1066
if (!fej9->canRememberClass(tempreceiverClass) ||
1067
!fej9->canRememberClass(callSiteClass))
1068
{
1069
if (comp()->trace(OMR::inlining))
1070
traceMsg(comp(), "inliner: profiled class [%p] or callSiteClass [%p] cannot be rememberd in shared cache\n", tempreceiverClass, callSiteClass);
1071
continue;
1072
}
1073
}
1074
1075
TR_VirtualGuardSelection *guard = NULL;
1076
if (preferMethodTest)
1077
guard = new (comp()->trHeapMemory()) TR_VirtualGuardSelection(TR_ProfiledGuard, TR_MethodTest, tempreceiverClass);
1078
else
1079
guard = new (comp()->trHeapMemory()) TR_VirtualGuardSelection(TR_ProfiledGuard, TR_VftTest, tempreceiverClass);
1080
1081
// if the previous value was from the interpreter profiler
1082
// don't apply the optimization
1083
TR_ByteCodeInfo &bcInfo = _bcInfo; //callNode->getByteCodeInfo();
1084
if (valueInfo->getTopProbability() == 1.0f && valueInfo->getProfiler()->getSource() < LastProfiler)
1085
guard->setIsHighProbablityProfiledGuard();
1086
1087
heuristicTrace(inliner->tracer(),"Creating a profiled call. callee Symbol %p frequencyadjustment %f",_initialCalleeSymbol, val);
1088
addTarget(comp()->trMemory(),inliner,guard,targetMethod,tempreceiverClass,heapAlloc,val);
1089
1090
if (comp()->getOption(TR_DisableMultiTargetInlining))
1091
return;
1092
}
1093
else // if we're below the above threshold, lets stop considering call targets
1094
{
1095
if (comp()->trace(OMR::inlining))
1096
traceMsg(comp(), "bailing, below inlining threshold\n");
1097
break;
1098
}
1099
1100
}
1101
1102
}
1103
1104
1105
void TR_ProfileableCallSite::findSingleProfiledMethod(ListIterator<TR_ExtraAddressInfo>& sortedValuesIt, TR_AddressInfo * valueInfo, TR_InlinerBase* inliner)
1106
{
1107
if (!comp()->cg()->getSupportsProfiledInlining())
1108
{
1109
return;
1110
}
1111
1112
uint32_t totalFrequency = valueInfo->getTotalFrequency();
1113
1114
if (totalFrequency<=0)
1115
{
1116
return;
1117
}
1118
TR_OpaqueClassBlock* callSiteClass = _receiverClass ? _receiverClass : getClassFromMethod();
1119
TR_ASSERT_FATAL(!isInterface(), "Interface call site called TR_ProfileableCallSite::findSingleProfiledMethod()");
1120
if (!callSiteClass || (TR::Compiler->cls.isInterfaceClass(comp(), callSiteClass) && isCallingObjectMethod() != TR_yes))
1121
{
1122
// TR_J9VirtualCallSite::findCallSiteTarget() should refine the _receiverClass, but if it failed, we need to abort this inlining
1123
if (callSiteClass && comp()->trace(OMR::inlining))
1124
traceMsg(comp(), "callSiteClass [%p] is an interface making it impossible to confirm correct context for any profiled class\n", callSiteClass);
1125
return;
1126
}
1127
1128
// first let's do sanity test on all profiled targets
1129
if (comp()->trace(OMR::inlining))
1130
traceMsg(comp(), "No decisive class profiling info for the virtual method, we'll try to see if more than one class uses the same method implementation.\n");
1131
1132
bool classValuesAreSane = true;
1133
for (TR_ExtraAddressInfo *profiledInfo = sortedValuesIt.getFirst(); profiledInfo != NULL; profiledInfo = sortedValuesIt.getNext())
1134
{
1135
TR_OpaqueClassBlock *clazz = (TR_OpaqueClassBlock *) profiledInfo->_value;
1136
bool isClassObsolete = comp()->getPersistentInfo()->isObsoleteClass((void*)clazz, comp()->fe());
1137
if (isClassObsolete)
1138
{
1139
classValuesAreSane = false;
1140
break;
1141
}
1142
1143
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp()->fe());
1144
// need to be able to store class chains for these methods
1145
if (comp()->compileRelocatableCode())
1146
{
1147
if (clazz && comp()->getOption(TR_UseSymbolValidationManager))
1148
if (!comp()->getSymbolValidationManager()->addProfiledClassRecord(clazz))
1149
{
1150
classValuesAreSane = false;
1151
break;
1152
}
1153
1154
if (!fej9->canRememberClass(clazz) ||
1155
!fej9->canRememberClass(callSiteClass))
1156
{
1157
classValuesAreSane = false;
1158
break;
1159
}
1160
}
1161
}
1162
1163
if (!classValuesAreSane)
1164
return;
1165
1166
if (comp()->trace(OMR::inlining))
1167
traceMsg(comp(), "OK, all classes check out, we'll try to get their method implementations.\n");
1168
1169
TR_ScratchList<TR_AddressInfo::ProfiledMethod> methodsList(comp()->trMemory());
1170
// this API doesn't do a sort
1171
valueInfo->getMethodsList(comp(), _callerResolvedMethod, callSiteClass, _vftSlot, &methodsList);
1172
1173
int numMethods = methodsList.getSize();
1174
1175
if (comp()->trace(OMR::inlining))
1176
traceMsg(comp(), "OK, all classes check out, we'll try to get their method implementations (%d).\n", numMethods);
1177
1178
1179
ListIterator<TR_AddressInfo::ProfiledMethod> methodValuesIt(&methodsList);
1180
TR_AddressInfo::ProfiledMethod *profiledMethodInfo;
1181
TR_AddressInfo::ProfiledMethod *bestMethodInfo = methodValuesIt.getFirst();
1182
1183
float methodProbability = .0f;
1184
1185
if (bestMethodInfo)
1186
{
1187
for (profiledMethodInfo = methodValuesIt.getNext(); profiledMethodInfo != NULL; profiledMethodInfo = methodValuesIt.getNext())
1188
{
1189
if (profiledMethodInfo->_frequency > bestMethodInfo->_frequency)
1190
bestMethodInfo = profiledMethodInfo;
1191
}
1192
1193
methodProbability = (float)bestMethodInfo->_frequency/(float)totalFrequency;
1194
1195
if (comp()->trace(OMR::inlining))
1196
{
1197
TR_ResolvedMethod *targetMethod = (TR_ResolvedMethod *)bestMethodInfo->_value;
1198
traceMsg(comp(), "Found a target method %s with probability of %f%%.\n",
1199
targetMethod->signature(comp()->trMemory()), methodProbability * 100.0);
1200
}
1201
1202
static const char* userMinProfiledCallFreq = feGetEnv("TR_MinProfiledCallFrequency");
1203
static const float minProfiledCallFrequency = userMinProfiledCallFreq ? atof (userMinProfiledCallFreq) : MIN_PROFILED_CALL_FREQUENCY;
1204
1205
if (methodProbability >= minProfiledCallFrequency)
1206
{
1207
TR_ResolvedMethod *targetMethod = (TR_ResolvedMethod *)bestMethodInfo->_value;
1208
TR_OpaqueClassBlock *targetClass = targetMethod->classOfMethod();
1209
1210
if (targetMethod && targetClass)
1211
{
1212
TR_VirtualGuardSelection *guard = new (comp()->trHeapMemory()) TR_VirtualGuardSelection(TR_ProfiledGuard, TR_MethodTest, targetClass);
1213
addTarget(comp()->trMemory(), inliner, guard, targetMethod, targetClass, heapAlloc, methodProbability);
1214
if (comp()->trace(OMR::inlining))
1215
{
1216
TR_ResolvedMethod *targetMethod = (TR_ResolvedMethod *)bestMethodInfo->_value;
1217
traceMsg(comp(), "Added target method %s with probability of %f%%.\n",
1218
targetMethod->signature(comp()->trMemory()), methodProbability * 100.0);
1219
char* sig = TR::Compiler->cls.classSignature(comp(), targetClass, comp()->trMemory());
1220
traceMsg(comp(), "target class %s\n", sig);
1221
}
1222
return;
1223
}
1224
}
1225
}
1226
else if (comp()->trace(OMR::inlining))
1227
traceMsg(comp(), "Failed to find any methods compatible with callsite class %p signature %s\n", callSiteClass, TR::Compiler->cls.classSignature(comp(), callSiteClass, comp()->trMemory()));
1228
}
1229
1230
bool TR_ProfileableCallSite::findProfiledCallTargets (TR_CallStack *callStack, TR_InlinerBase* inliner)
1231
{
1232
heuristicTrace(inliner->tracer(),"Looking for a profiled Target %p \n", this);
1233
TR_ValueProfileInfoManager * profileManager = TR_ValueProfileInfoManager::get(comp());
1234
1235
if (!profileManager)
1236
{
1237
heuristicTrace(inliner->tracer()," no profileManager %p\n", this);
1238
return false;
1239
}
1240
1241
TR_AddressInfo *valueInfo = static_cast<TR_AddressInfo*>(profileManager->getValueInfo(_bcInfo, comp(), AddressInfo));
1242
1243
if(!valueInfo || comp()->getOption(TR_DisableProfiledInlining))
1244
{
1245
heuristicTrace(inliner->tracer()," no valueInfo or valueInfo is not of AddressInfo type or TR_DisableProfiledInlining specified for %p\n", this);
1246
return false;
1247
}
1248
1249
1250
1251
TR_ScratchList<TR_ExtraAddressInfo> valuesSortedByFrequency(comp()->trMemory());
1252
valueInfo->getSortedList(comp(), &valuesSortedByFrequency);
1253
ListIterator<TR_ExtraAddressInfo> sortedValuesIt(&valuesSortedByFrequency);
1254
1255
uint32_t totalFrequency = valueInfo->getTotalFrequency();
1256
((TR_J9InlinerTracer *)inliner->tracer())->dumpProfiledClasses(sortedValuesIt, totalFrequency);
1257
1258
//@TODO: put in a separate function
1259
if (inliner->isEDODisableInlinedProfilingInfo() && _callerResolvedMethod != comp()->getCurrentMethod())
1260
{
1261
// if the previous value was from the interpreter profiler
1262
// don't devirtualize
1263
if (valueInfo->getProfiler()->getSource() == LastProfiler)
1264
{
1265
inliner->tracer()->insertCounter(EDO_Callee,_callNodeTreeTop);
1266
heuristicTrace(inliner->tracer()," EDO callsite %p, so not inlineable\n", this);
1267
return false;
1268
}
1269
}
1270
1271
findSingleProfiledReceiver(sortedValuesIt, valueInfo, inliner);
1272
if (!numTargets())
1273
{
1274
findSingleProfiledMethod(sortedValuesIt, valueInfo, inliner);
1275
}
1276
1277
return numTargets();
1278
}
1279
1280
1281
1282