Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/ilgen/IlGenerator.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 "codegen/CodeGenerator.hpp"
24
#include "compile/InlineBlock.hpp"
25
#include "compile/Method.hpp"
26
#include "compile/ResolvedMethod.hpp"
27
#include "control/Recompilation.hpp"
28
#include "control/RecompilationInfo.hpp"
29
#include "env/PersistentCHTable.hpp"
30
#include "env/CompilerEnv.hpp"
31
#include "il/Node.hpp"
32
#include "il/Node_inlines.hpp"
33
#include "il/ParameterSymbol.hpp"
34
#include "il/TreeTop.hpp"
35
#include "il/TreeTop_inlines.hpp"
36
#include "ilgen/IlGeneratorMethodDetails_inlines.hpp"
37
#include "infra/Cfg.hpp"
38
#include "infra/Checklist.hpp"
39
#include "env/VMJ9.h"
40
#include "ilgen/J9ByteCodeIlGenerator.hpp"
41
#include "optimizer/BoolArrayStoreTransformer.hpp"
42
#include "ras/DebugCounter.hpp"
43
#include "optimizer/TransformUtil.hpp"
44
#include "env/JSR292Methods.h"
45
46
#define OPT_DETAILS "O^O ILGEN: "
47
48
TR_J9ByteCodeIlGenerator::TR_J9ByteCodeIlGenerator(
49
TR::IlGeneratorMethodDetails & methodDetails, TR::ResolvedMethodSymbol * methodSymbol, TR_J9VMBase * fe, TR::Compilation * comp,
50
TR::SymbolReferenceTable * symRefTab, bool forceClassLookahead, TR_InlineBlocks *blocksToInline, int32_t argPlaceholderSlot) //TR_ScratchList<TR_InlineBlock> *blocksToInline)
51
: TR_J9ByteCodeIteratorWithState(methodSymbol, fe, comp),
52
_methodDetails(methodDetails),
53
_symRefTab(symRefTab),
54
_classLookaheadSymRefTab(NULL),
55
_blockAddedVisitCount(comp->incVisitCount()),
56
_generateWriteBarriersForGC(TR::Compiler->om.writeBarrierType() != gc_modron_wrtbar_none),
57
_generateWriteBarriersForFieldWatch(comp->getOption(TR_EnableFieldWatch)),
58
_generateReadBarriersForFieldWatch(comp->getOption(TR_EnableFieldWatch)),
59
_suppressSpineChecks(false),
60
_implicitMonitorExits(comp->trMemory()),
61
_finalizeCallsBeforeReturns(comp->trMemory()),
62
_classInfo(0),
63
_blocksToInline(blocksToInline),
64
_argPlaceholderSlot(argPlaceholderSlot),
65
_intrinsicErrorHandling(0),
66
_invokeSpecialInterface(NULL),
67
_invokeSpecialInterfaceCalls(NULL),
68
_invokeSpecialSeen(false),
69
_couldOSRAtNextBC(false),
70
_processedOSRNodes(NULL),
71
_invokeHandleCalls(NULL),
72
_invokeHandleGenericCalls(NULL),
73
_invokeDynamicCalls(NULL),
74
_ilGenMacroInvokeExactCalls(NULL),
75
_methodHandleInvokeCalls(NULL)
76
{
77
static const char *noLookahead = feGetEnv("TR_noLookahead");
78
_noLookahead = (noLookahead || comp->getOption(TR_DisableLookahead)) ? true : false;
79
_thisChanged = false;
80
if (
81
(forceClassLookahead ||
82
(comp->getNeedsClassLookahead() && !_noLookahead &&
83
((comp->getMethodHotness() >= scorching) ||
84
(comp->couldBeRecompiled() && (comp->getMethodHotness() >= hot ))))))
85
{
86
bool allowForAOT = comp->getOption(TR_UseSymbolValidationManager);
87
_classInfo = comp->getPersistentInfo()->getPersistentCHTable()->findClassInfoAfterLocking(method()->containingClass(), comp, allowForAOT);
88
}
89
else
90
{
91
if (!comp->getOption(TR_PerformLookaheadAtWarmCold))
92
_noLookahead = true;
93
}
94
95
if (argPlaceholderSlot == -1)
96
{
97
_argPlaceholderSignatureOffset = 0xdead1127;
98
}
99
else
100
{
101
// Compute _argPlaceholderSignatureOffset
102
//
103
char *signatureChars = _methodSymbol->getResolvedMethod()->signatureChars();
104
TR_ASSERT(*signatureChars = '(', "assertion failure");
105
char *curArg = signatureChars+1;
106
int32_t argSlotsSkipped = methodSymbol->isStatic()? 0 : 1; // receiver doesn't appear in the signature
107
while (argSlotsSkipped < argPlaceholderSlot)
108
{
109
switch (*curArg)
110
{
111
case 'D':
112
case 'J':
113
argSlotsSkipped += 2;
114
break;
115
default:
116
argSlotsSkipped += 1;
117
break;
118
}
119
curArg = nextSignatureArgument(curArg);
120
}
121
_argPlaceholderSignatureOffset = curArg - signatureChars;
122
}
123
for( int i=0 ; i < _numDecFormatRenames ; i++ )
124
{
125
_decFormatRenamesDstSymRef[i] = NULL;
126
}
127
if (comp->getOption(TR_EnableOSR)
128
&& !comp->isPeekingMethod()
129
&& comp->isOSRTransitionTarget(TR::postExecutionOSR)
130
&& !_cannotAttemptOSR)
131
_processedOSRNodes = new (trStackMemory()) TR::NodeChecklist(comp);
132
}
133
134
bool
135
TR_J9ByteCodeIlGenerator::genIL()
136
{
137
if (comp()->isOutermostMethod())
138
comp()->reportILGeneratorPhase();
139
140
TR::StackMemoryRegion stackMemoryRegion(*trMemory());
141
142
comp()->setCurrentIlGenerator(this);
143
144
bool success = internalGenIL();
145
146
if (success && !comp()->isPeekingMethod())
147
{
148
TR_SharedCache *sc = fej9()->sharedCache();
149
if (sc)
150
{
151
/*
152
* if DelayRelocationForAOT don't persist iprofiler info now.
153
* instead, persist iprofiler info when loading the aot compilation
154
*/
155
if (comp()->getOption(TR_DisableDelayRelocationForAOTCompilations) || !fej9()->shouldDelayAotLoad())
156
{
157
sc->persistIprofileInfo(_methodSymbol->getResolvedMethodSymbol(), comp());
158
}
159
}
160
}
161
162
/*
163
* If we're generating IL for DecimalformatHelper.formatAsDouble(Float), replace
164
* the necessary fields, statics, and methods appropriately. This is part of
165
* the optimization that replaces df.format(bd.doubleValue()) and
166
* df.format(bd.floatValue()) with, respectively,
167
* DecimalFormatHelper.formatAsDouble(df, bd) and
168
* DecimalFormatHelper.formatAsFloat(df, bd) in which bd is a BigDecimal object
169
* and df is DecimalFormat object. The latter pair of calls are much faster than
170
* the former ones because it avoids many of the conversions that the former
171
* performs.
172
*/
173
if (success)
174
{
175
const char* methodName = _methodSymbol->signature(comp()->trMemory());
176
if (!strcmp(methodName, "com/ibm/jit/DecimalFormatHelper.formatAsDouble(Ljava/text/DecimalFormat;Ljava/math/BigDecimal;)Ljava/lang/String;") ||
177
!strcmp(methodName, "com/ibm/jit/DecimalFormatHelper.formatAsFloat(Ljava/text/DecimalFormat;Ljava/math/BigDecimal;)Ljava/lang/String;"))
178
success = success && replaceMembersOfFormat();
179
}
180
181
if (success && !comp()->isPeekingMethod())
182
{
183
_methodSymbol->clearProfilingOffsetInfo();
184
for (TR::Block *block = _methodSymbol->getFirstTreeTop()->getEnclosingBlock(); block; block = block->getNextBlock())
185
_methodSymbol->addProfilingOffsetInfo(block->getEntry()->getNode()->getByteCodeIndex(), block->getExit()->getNode()->getByteCodeIndex());
186
}
187
188
comp()->setCurrentIlGenerator(0);
189
190
return success;
191
}
192
193
bool TR_J9ByteCodeIlGenerator::internalGenIL()
194
{
195
_stack = new (trStackMemory()) TR_Stack<TR::Node *>(trMemory(), 20, false, stackAlloc);
196
197
bool success = false;
198
199
if ((method()->isNewInstanceImplThunk() || debug("testGenNewInstanceImplThunk")))
200
{
201
success = genNewInstanceImplThunk();
202
if (!success) // must jit the body (throw instantiation exception)
203
success = genILFromByteCodes();
204
else if (comp()->getOption(TR_EnableOSR) && !comp()->isPeekingMethod() && !comp()->getOption(TR_FullSpeedDebug))
205
_methodSymbol->setCannotAttemptOSR(0);
206
207
return success;
208
}
209
210
TR::RecognizedMethod recognizedMethod = _methodSymbol->getRecognizedMethod();
211
if (recognizedMethod != TR::unknownMethod)
212
{
213
if (recognizedMethod == TR::com_ibm_jit_JITHelpers_supportsIntrinsicCaseConversion && !TR::Compiler->om.canGenerateArraylets())
214
{
215
if (performTransformation(comp(), "O^O IlGenerator: Generate com/ibm/jit/JITHelpers.supportsIntrinsicCaseConversion\n"))
216
{
217
genHWOptimizedStrProcessingAvailable();
218
return true;
219
}
220
}
221
222
if (recognizedMethod == TR::com_ibm_dataaccess_DecimalData_JITIntrinsicsEnabled)
223
{
224
if (performTransformation(comp(), "O^O IlGenerator: Generate com/ibm/dataaccess/DecimalData.JITIntrinsicsEnabled\n"))
225
{
226
genJITIntrinsicsEnabled();
227
return true;
228
}
229
}
230
231
if (recognizedMethod == TR::com_ibm_rmi_io_FastPathForCollocated_isVMDeepCopySupported)
232
{
233
if (performTransformation(comp(), "O^O IlGenerator: Generate com/ibm/rmi/io/FastPathForCollocated/isVMDeepCopySupported\n"))
234
{
235
genIsORBDeepCopyAvailable();
236
return true;
237
}
238
}
239
240
if (!comp()->getOption(TR_DisableInliningOfNatives))
241
{
242
// If we're inlining then there are some stack walking routines that can be made faster
243
// by avoiding the stack walk.
244
//
245
TR_ResolvedMethod * caller1 = method()->owningMethod();
246
TR_ResolvedMethod * caller = caller1 ? caller1->owningMethod() : 0;
247
248
if( caller && caller1)
249
{
250
TR_OpaqueClassBlock *callerClass = caller ? caller->classOfMethod() : 0;
251
TR_OpaqueClassBlock *callerClass1 = caller1 ? caller1->classOfMethod() : 0;
252
253
bool doIt = !(fej9()->stackWalkerMaySkipFrames(caller->getPersistentIdentifier(),callerClass) ||
254
fej9()->stackWalkerMaySkipFrames(caller1->getPersistentIdentifier(),callerClass1));
255
256
257
if (doIt && !comp()->compileRelocatableCode())
258
{
259
if (recognizedMethod == TR::java_lang_ClassLoader_callerClassLoader)
260
{
261
createGeneratedFirstBlock();
262
// check for bootstrap classloader, if so
263
// return null (see semantics of ClassLoader.callerClassLoader())
264
//
265
if (fej9()->isClassLoadedBySystemClassLoader(caller->classOfMethod()))
266
{
267
loadConstant(TR::aconst, (void *)0);
268
}
269
else
270
{
271
loadSymbol(TR::aload, symRefTab()->findOrCreateClassLoaderSymbolRef(caller));
272
}
273
genTreeTop(TR::Node::create(method()->returnOpCode(), 1, pop()));
274
return true;
275
}
276
if (recognizedMethod == TR::com_ibm_oti_vm_VM_callerClass)
277
{
278
createGeneratedFirstBlock();
279
loadConstant(TR::aconst, caller->classOfMethod());
280
genTreeTop(TR::Node::create(method()->returnOpCode(), 1, pop()));
281
return true;
282
}
283
}
284
}
285
}
286
}
287
if (method()->isJNINative())
288
return genJNIIL();
289
290
return genILFromByteCodes();
291
}
292
293
bool
294
TR_J9ByteCodeIlGenerator::genILFromByteCodes()
295
{
296
// first passthrough of the byte code to see if this pointer has been changed
297
if (isThisChanged())
298
_thisChanged = true;
299
300
initialize();
301
302
// don't go peeking into massive methods
303
if (comp()->isPeekingMethod() && _maxByteCodeIndex >= USHRT_MAX/8)
304
return false;
305
306
// FSD sync object support
307
//
308
// Ideally, I'd like the sync object in FSD to work exactly as it does in the interpreter.
309
// This means that the sync object (receiver for instance methods, declaring class for
310
// static methods) is always stored in synthetic local N+1 after the stack frame is built,
311
// and is re-read from memory before use in the method monitor exit. If it's a lot of trouble
312
// to place it at N+1, the decompiler can read it from somewhere else as long as you can point me there
313
// via the metadata. Whatever slot is used, it must be marked as a GC reference even when it is a class.
314
// If we eventually support hot code replace which does not flush the JIT code caches, we'll
315
// need to do some more work for static methods, since the class sync object in static sync frames must always be the "current" class.
316
//
317
if (_methodSymbol->isSynchronised())
318
{
319
if (comp()->getOption(TR_FullSpeedDebug) || !comp()->getOption(TR_DisableLiveMonitorMetadata))
320
{
321
TR::SymbolReference * symRef;
322
if (comp()->getOption(TR_FullSpeedDebug))
323
symRef = symRefTab()->findOrCreateAutoSymbol(_methodSymbol, _methodSymbol->getSyncObjectTempIndex(), TR::Address);
324
else
325
symRef = symRefTab()->createTemporary(_methodSymbol, TR::Address);
326
327
_methodSymbol->setSyncObjectTemp(symRef);
328
329
if (!comp()->getOption(TR_DisableLiveMonitorMetadata))
330
{
331
symRef->setHoldsMonitoredObjectForSyncMethod();
332
comp()->addAsMonitorAuto(symRef, true);
333
}
334
}
335
}
336
337
if (_methodSymbol->getResolvedMethod()->isNonEmptyObjectConstructor())
338
{
339
if (comp()->getOption(TR_FullSpeedDebug))
340
{
341
TR::SymbolReference *symRef = symRefTab()->findOrCreateAutoSymbol(_methodSymbol, _methodSymbol->getThisTempForObjectCtorIndex(), TR::Address);
342
_methodSymbol->setThisTempForObjectCtor(symRef);
343
symRef->getSymbol()->setThisTempForObjectCtor();
344
}
345
}
346
347
_staticFieldReferenceEncountered = false;
348
_staticMethodInvokeEncountered = false;
349
350
// Allocate zero-length bit vectors before walker so that the bit vectors can grow on the right
351
// stack memory region
352
//
353
_methodHandleInvokeCalls = new (trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc, growable);
354
_invokeHandleCalls = new (trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc, growable);
355
_invokeHandleGenericCalls = new (trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc, growable);
356
_invokeDynamicCalls = new (trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc, growable);
357
_ilGenMacroInvokeExactCalls = new (trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc, growable);
358
359
TR::Block * lastBlock = walker(0);
360
361
if (hasExceptionHandlers())
362
lastBlock = genExceptionHandlers(lastBlock);
363
364
_bcIndex = 0;
365
366
_methodSymbol->setFirstTreeTop(blocks(0)->getEntry());
367
368
if (inliningCheckIfFinalizeObjectIsBeneficial())
369
{
370
inlineJitCheckIfFinalizeObject(blocks(0));
371
}
372
373
prependEntryCode(blocks(0));
374
375
if (!comp()->getOption(TR_DisableGuardedCountingRecompilations) &&
376
comp()->getRecompilationInfo() && comp()->getRecompilationInfo()->shouldBeCompiledAgain() &&
377
!comp()->getRecompilationInfo()->isRecompilation() && // only do it for first time compilations
378
(!comp()->getPersistentInfo()->_countForRecompile || comp()->getOption(TR_EnableMultipleGCRPeriods)) &&
379
comp()->isOutermostMethod() &&
380
comp()->getOptions()->getInsertGCRTrees() &&
381
!comp()->isDLT() && !method()->isJNINative())
382
{
383
// GCR filtering: Do not insert GCR trees for methods that are small and have no calls
384
// This code is better suited for CompilationThread.cpp
385
// but we need support from VM to tell us that a method has calls
386
if (_methodSymbol->mayHaveInlineableCall() ||
387
// Possible tweak: increase the threshold for methods that do not have loops
388
_maxByteCodeIndex > TR::Options::_smallMethodBytecodeSizeThresholdForCold ||
389
_methodSymbol->mayHaveLoops())
390
{
391
prependGuardedCountForRecompilation(comp()->getStartTree()->getNode()->getBlock());
392
comp()->getOptimizationPlan()->resetAddToUpgradeQueue(); // do not add to upgrade queue methods for which we used GCR
393
// stats
394
comp()->getPersistentInfo()->incNumGCRBodies();
395
}
396
else
397
{
398
//TR_VerboseLog::writeLineLocked(TR_Vlog_PERF,"Saved a GCR gen body nmayHaveInlineableCall=%d mayHaveLoops=%d _maxByteCodeIndex=%d\n", _methodSymbol->mayHaveInlineableCall(), _methodSymbol->mayHaveLoops(), _maxByteCodeIndex);
399
// stats
400
comp()->getPersistentInfo()->incNumGCRSaves();
401
}
402
}
403
404
// Logic related to SamplingJProfiling
405
//
406
if (comp()->isOutermostMethod() && // Only do it once for the method to be compiled
407
!comp()->getOptions()->isDisabled(OMR::samplingJProfiling)) // If heuristic enabled samplingJProfiling for this body
408
{
409
// Verify that the GCR logic above actually inserted GCR trees
410
// or that this is a DLT body
411
// Also verify that method has bytecodes we want to profile (invokes/checkcasts/branches)
412
//
413
if ((comp()->isDLT() || (comp()->getRecompilationInfo() &&
414
comp()->getRecompilationInfo()->getJittedBodyInfo()->getUsesGCR()))
415
&& (_methodSymbol->mayHaveInlineableCall()
416
|| _methodSymbol->hasCheckcastsOrInstanceOfs()
417
|| _methodSymbol->hasBranches())
418
)
419
{
420
// Disable inlining to compile fast and avoid the bug with not profiling on the fast path
421
comp()->getOptions()->setDisabled(OMR::inlining, true);
422
}
423
else // Canot profile or there is nothing to profile; take corrective actions
424
{
425
// Disable the samplingJProfiling opt
426
comp()->getOptions()->setDisabled(OMR::samplingJProfiling, true);
427
428
// If the opt level was reduced to cold solely because we wanted
429
// to do samplingJProfiling then we must move the opt level back to warm
430
if (comp()->getOptimizationPlan()->isDowngradedDueToSamplingJProfiling())
431
{
432
comp()->changeOptLevel(warm);
433
comp()->getOptimizationPlan()->setDowngradedDueToSamplingJProfiling(false);
434
comp()->getOptimizationPlan()->setOptLevelDowngraded(false);
435
}
436
}
437
}
438
439
440
// Code pertaining to the secondary/upgrade compilation queue
441
// If the method is small, doesn't have loops or calls, then do not try to upgrade it
442
if (comp()->isOutermostMethod() && comp()->getOptimizationPlan()->shouldAddToUpgradeQueue())
443
{
444
if (!_methodSymbol->mayHaveInlineableCall() && !_methodSymbol->mayHaveLoops() &&
445
_maxByteCodeIndex <= TR::Options::_smallMethodBytecodeSizeThresholdForCold)
446
comp()->getOptimizationPlan()->resetAddToUpgradeQueue();
447
}
448
449
// the optimizer assumes that the ilGenerator doesn't gen code for
450
// unreachable blocks. An exception handler may be unreachable.
451
//
452
if (hasExceptionHandlers())
453
cfg()->removeUnreachableBlocks();
454
455
int32_t fpIndex = hasFPU() ? -1 : findFloatingPointInstruction();
456
if (fpIndex != -1) _unimplementedOpcode = _code[fpIndex];
457
458
if (_unimplementedOpcode)
459
{
460
_methodSymbol->setUnimplementedOpcode(_unimplementedOpcode);
461
462
if (debug("traceInfo"))
463
{
464
if (_unimplementedOpcode == 255)
465
diagnostic("\nUnimplemented opcodes found\n");
466
else
467
diagnostic("\nUnimplemented opcode found: %s(%d)\n",
468
((TR_J9VM *)fej9())->getByteCodeName(_unimplementedOpcode), _unimplementedOpcode);
469
}
470
471
if (!debug("continueWithUnimplementedOpCode"))
472
return false;
473
}
474
475
//if (!_thisChanged)
476
//setThisNonNullProperty(_methodSymbol->getFirstTreeTop(), comp());
477
478
bool needMonitor = _methodSymbol->isSynchronised() && !comp()->getOption(TR_DisableLiveMonitorMetadata);
479
int32_t numMonents = 0;
480
int32_t numMonexits = 0;
481
bool primitive = true;
482
TR::TreeTop *monentStore = NULL;
483
TR::TreeTop *monexitStore = NULL;
484
TR::Node *monentTree = NULL;
485
TR::Node *monexitTree = NULL;
486
TR::TreeTop *currTree = _methodSymbol->getFirstTreeTop()->getNextTreeTop();
487
488
List<TR::SymbolReference> autoOrParmSymRefList(comp()->trMemory());
489
TR_ScratchList<TR::TreeTop> unresolvedCheckcastTopsNeedingNullGuard(comp()->trMemory());
490
TR_ScratchList<TR::TreeTop> unresolvedInstanceofTops(comp()->trMemory());
491
TR_ScratchList<TR::TreeTop> invokeSpecialInterfaceTops(comp()->trMemory());
492
TR::NodeChecklist evaluatedInvokeSpecialCalls(comp());
493
TR::NodeChecklist evaluatedMethodHandleInvokeCalls(comp());
494
TR_BoolArrayStoreTransformer::NodeSet bstoreiUnknownArrayTypeNodes(std::less<TR::Node *>(), comp()->trMemory()->currentStackRegion());
495
TR_BoolArrayStoreTransformer::NodeSet bstoreiBoolArrayTypeNodes(std::less<TR::Node *>(), comp()->trMemory()->currentStackRegion());
496
TR_BoolArrayStoreTransformer boolArrayStoreTransformer(&bstoreiUnknownArrayTypeNodes, &bstoreiBoolArrayTypeNodes);
497
498
for (; currTree != NULL; currTree = currTree->getNextTreeTop())
499
{
500
TR::Node *currNode = currTree->getNode();
501
TR::ILOpCode opcode = currNode->getOpCode();
502
503
if (currNode->getNumChildren() >= 1
504
&& currNode->getFirstChild()->getOpCode().isCall()
505
&& !currNode->getFirstChild()->getSymbol()->castToMethodSymbol()->isHelper()
506
&& _methodHandleInvokeCalls->isSet(currNode->getFirstChild()->getByteCodeIndex())
507
&& !evaluatedMethodHandleInvokeCalls.contains(currNode->getFirstChild()))
508
{
509
expandMethodHandleInvokeCall(currTree);
510
evaluatedMethodHandleInvokeCalls.add(currNode->getFirstChild());
511
continue;
512
}
513
514
if ((opcode.isStoreDirect() && opcode.hasSymbolReference() && currNode->getSymbolReference()->getSymbol()->isAutoOrParm()) ||
515
opcode.isCheckCast())
516
{
517
TR::SymbolReference *symRef = currNode->getSymbolReference();
518
TR::Node *typeNode = NULL;
519
if (opcode.isStoreDirect())
520
typeNode = currNode->getFirstChild(); // store auto
521
else typeNode = currNode->getSecondChild(); // checkcast
522
if (boolArrayStoreTransformer.isAnyDimensionBoolArrayNode(typeNode))
523
boolArrayStoreTransformer.setHasBoolArrayAutoOrCheckCast();
524
else if (boolArrayStoreTransformer.isAnyDimensionByteArrayNode(typeNode))
525
boolArrayStoreTransformer.setHasByteArrayAutoOrCheckCast();
526
527
if (opcode.isStoreDirect() && symRef->getSymbol()->isParm() && currNode->getDataType() == TR::Address)
528
{
529
int lhsLength;
530
int rhsLength;
531
const char *lhsSig = currNode->getTypeSignature(lhsLength, stackAlloc, false /* parmAsAuto */);
532
const char *rhsSig = typeNode->getTypeSignature(rhsLength, stackAlloc, true /* parmAsAuto */);
533
if (!lhsSig || !rhsSig || lhsLength != rhsLength || strncmp(lhsSig, rhsSig, lhsLength))
534
boolArrayStoreTransformer.setHasVariantArgs();
535
}
536
}
537
else if (opcode.getOpCodeValue() == TR::bstorei && currNode->getSymbolReference()->getCPIndex() == -1
538
&& currNode->getFirstChild()->isInternalPointer())
539
{
540
TR::Node *arrayBase = currNode->getFirstChild()->getFirstChild();
541
if (arrayBase->getOpCode().hasSymbolReference())
542
{
543
if (boolArrayStoreTransformer.isBoolArrayNode(arrayBase))
544
{
545
if (comp()->getOption(TR_TraceILGen))
546
traceMsg(comp(), "bstorei node n%dn is bool array store\n", currNode->getGlobalIndex());
547
bstoreiBoolArrayTypeNodes.insert(currNode);
548
}
549
else if (!boolArrayStoreTransformer.isByteArrayNode(arrayBase))
550
bstoreiUnknownArrayTypeNodes.insert(currNode);
551
}
552
else
553
bstoreiUnknownArrayTypeNodes.insert(currNode);
554
}
555
556
if (currNode->getOpCodeValue() == TR::checkcast
557
&& currNode->getSecondChild()->getOpCodeValue() == TR::loadaddr
558
&& currNode->getSecondChild()->getSymbolReference()->isUnresolved()
559
&& // check whether the checkcast class is valuetype. Expansion is only needed for checkcast to reference type.
560
(!TR::Compiler->om.areValueTypesEnabled()
561
|| !TR::Compiler->cls.isClassRefValueType(comp(), method()->classOfMethod(), currNode->getSecondChild()->getSymbolReference()->getCPIndex())))
562
{
563
unresolvedCheckcastTopsNeedingNullGuard.add(currTree);
564
}
565
else if (currNode->getOpCodeValue() == TR::treetop
566
&& currNode->getFirstChild()->getOpCodeValue() == TR::instanceof
567
&& currNode->getFirstChild()->getSecondChild()->getOpCodeValue() == TR::loadaddr
568
&& currNode->getFirstChild()->getSecondChild()->getSymbolReference()->isUnresolved())
569
{
570
unresolvedInstanceofTops.add(currTree);
571
}
572
else if (_invokeSpecialInterfaceCalls != NULL
573
&& currNode->getNumChildren() >= 1
574
&& currNode->getFirstChild()->getOpCode().isCallDirect()
575
&& !currNode->getFirstChild()->isPotentialOSRPointHelperCall()
576
&& _invokeSpecialInterfaceCalls->isSet(
577
currNode->getFirstChild()->getByteCodeIndex())
578
&& !evaluatedInvokeSpecialCalls.contains(currNode->getFirstChild()))
579
{
580
evaluatedInvokeSpecialCalls.add(currNode->getFirstChild());
581
invokeSpecialInterfaceTops.add(currTree);
582
}
583
584
// modify the vftChild
585
// If the receiver pointer is a simple load of an auto or parm, then clone
586
// it rather than incrementing its reference count. This can prevent the
587
// inliner from creating unnecessary temporaries. The special case is when
588
// there is a store to the auto or parm between the load of receiver pointer
589
//and the virtual function call
590
591
//keep track of the symbol references of auto or parm changed by stores
592
if(opcode.isStoreDirect() && opcode.hasSymbolReference())
593
{
594
TR::SymbolReference *symRef = currNode->getSymbolReference();
595
if (symRef && symRef->getSymbol()->isAutoOrParm())
596
autoOrParmSymRefList.add(symRef);
597
}
598
599
if(opcode.isResolveOrNullCheck())
600
{
601
TR::Node *firstChild = currNode->getFirstChild();
602
opcode = firstChild->getOpCode(); // the first child is indirect call to method
603
if (opcode.isCallIndirect()
604
&& !firstChild->getSymbol()->castToMethodSymbol()->isComputed())
605
{
606
TR::Node *receiver;
607
TR::Node *firstGrandChild = firstChild->getFirstChild(); // firstGrandChild is the vft child
608
receiver = firstGrandChild->getFirstChild();
609
TR::ILOpCode receiverOpcode = receiver->getOpCode();
610
TR::SymbolReference *symRef = NULL;
611
if(receiverOpcode.hasSymbolReference() && receiverOpcode.isLoadVarDirect())
612
symRef = receiver->getSymbolReference();
613
bool canCopyReceiver =symRef && symRef->getSymbol()->isAutoOrParm() && !autoOrParmSymRefList.find(symRef);
614
if (canCopyReceiver)
615
{
616
TR::Node *newReceiver = TR::Node::copy(receiver);
617
newReceiver->setReferenceCount(1);
618
firstGrandChild->setChild(0, newReceiver);
619
receiver->decReferenceCount();
620
}
621
}
622
}
623
624
if (needMonitor && primitive)
625
{
626
if ((currNode->getOpCode().isStore() &&
627
currNode->getSymbol()->holdsMonitoredObject() &&
628
!currNode->isLiveMonitorInitStore()) || currNode->getOpCode().getOpCodeValue() == TR::monexitfence)
629
{
630
bool isMonent = currNode->getOpCode().getOpCodeValue() != TR::monexitfence;
631
if (isMonent)
632
monentStore = currTree;
633
else
634
monexitStore = currTree;
635
}
636
637
if ((currNode->getOpCodeValue() == TR::monexit) || (currNode->getOpCodeValue() == TR::monent))
638
{
639
if (currNode->getOpCodeValue() == TR::monexit)
640
{
641
if (numMonexits > 0)
642
{
643
primitive = false;
644
continue;
645
}
646
647
monexitTree = currNode;
648
numMonexits++;
649
}
650
else if (currNode->getOpCodeValue() == TR::monent)
651
{
652
if (numMonents > 0)
653
{
654
primitive = false;
655
continue;
656
}
657
658
monentTree = currNode;
659
numMonents++;
660
}
661
}
662
else if (currNode->getNumChildren() > 0 &&
663
currNode->getFirstChild()->getNumChildren() > 0 &&
664
((currNode->getFirstChild()->getOpCodeValue() == TR::monexit) || (currNode->getFirstChild()->getOpCodeValue() == TR::monent)))
665
{
666
if (currNode->getFirstChild()->getOpCodeValue() == TR::monexit)
667
{
668
if (numMonexits > 0)
669
{
670
primitive = false;
671
continue;
672
}
673
monexitTree = currNode->getFirstChild();
674
numMonexits++;
675
}
676
else if (currNode->getFirstChild()->getOpCodeValue() == TR::monent)
677
{
678
if (numMonents > 0)
679
{
680
primitive = false;
681
continue;
682
}
683
monentTree = currNode->getFirstChild();
684
numMonents++;
685
}
686
}
687
else if (currNode->exceptionsRaised() != 0 ||
688
currNode->canCauseGC())
689
{
690
primitive = false;
691
continue;
692
}
693
}
694
}
695
696
if( needMonitor)
697
{
698
if (primitive &&
699
monentTree &&
700
monexitTree &&
701
monentStore &&
702
monexitStore)
703
{
704
TR::SymbolReference *replaceSymRef = NULL;
705
if (monentStore->getNode()->getFirstChild()->getSymbolReference()->getSymbol()->isAutoOrParm())
706
replaceSymRef = monentStore->getNode()->getFirstChild()->getSymbolReference();
707
708
if (replaceSymRef)
709
{
710
if (monentTree->getFirstChild()->getSymbolReference()->getSymbol()->isAutoOrParm())
711
{
712
monentTree->getFirstChild()->setSymbolReference(replaceSymRef);
713
}
714
715
if (monexitTree->getFirstChild()->getSymbolReference()->getSymbol()->isAutoOrParm())
716
{
717
monexitTree->getFirstChild()->setSymbolReference(replaceSymRef);
718
}
719
720
TR::TreeTop *prev = monentStore->getPrevTreeTop();
721
TR::TreeTop *next = monentStore->getNextTreeTop();
722
monentStore->getNode()->recursivelyDecReferenceCount();
723
prev->join(next);
724
725
prev = monexitStore->getPrevTreeTop();
726
next = monexitStore->getNextTreeTop();
727
monexitStore->getNode()->recursivelyDecReferenceCount();
728
prev->join(next);
729
_methodSymbol->setSyncObjectTemp(NULL);
730
}
731
}
732
}
733
734
{
735
ListIterator<TR::TreeTop> it(&unresolvedCheckcastTopsNeedingNullGuard);
736
for (TR::TreeTop *tree = it.getCurrent(); tree != NULL; tree = it.getNext())
737
expandUnresolvedClassCheckcast(tree);
738
}
739
{
740
ListIterator<TR::TreeTop> it(&unresolvedInstanceofTops);
741
for (TR::TreeTop *tree = it.getCurrent(); tree != NULL; tree = it.getNext())
742
expandUnresolvedClassInstanceof(tree);
743
}
744
{
745
ListIterator<TR::TreeTop> it(&invokeSpecialInterfaceTops);
746
for (TR::TreeTop *tree = it.getCurrent(); tree != NULL; tree = it.getNext())
747
expandInvokeSpecialInterface(tree);
748
}
749
750
if (!bstoreiUnknownArrayTypeNodes.empty() || !bstoreiBoolArrayTypeNodes.empty())
751
boolArrayStoreTransformer.perform();
752
753
return true;
754
}
755
756
757
TR::Block *
758
TR_J9ByteCodeIlGenerator::cloneHandler(TryCatchInfo * handlerInfo, TR::Block * firstBlock, TR::Block *lastBlock, TR::Block *lastBlockInMethod, List<TR::Block> *clonedCatchBlocks)
759
{
760
TR_BlockCloner cloner(cfg());
761
handlerInfo->_firstBlock = cloner.cloneBlocks(firstBlock, lastBlock);
762
lastBlockInMethod->getExit()->join(handlerInfo->_firstBlock->getEntry());
763
handlerInfo->_lastBlock = lastBlockInMethod = cloner.getLastClonedBlock();
764
handlerInfo->_catchBlock = cloner.getToBlock(firstBlock);
765
766
TR::Block *cursorBlock = firstBlock;
767
while (cursorBlock != lastBlockInMethod)
768
{
769
clonedCatchBlocks->add(cursorBlock);
770
cursorBlock = cursorBlock->getNextBlock();
771
}
772
clonedCatchBlocks->add(cursorBlock);
773
774
cfg()->addSuccessorEdges(lastBlockInMethod);
775
return lastBlockInMethod;
776
}
777
778
779
780
TR::Block *
781
TR_J9ByteCodeIlGenerator::genExceptionHandlers(TR::Block * lastBlock)
782
{
783
bool trace = comp()->getOption(TR_TraceILGen);
784
_inExceptionHandler = true;
785
TR::SymbolReference * catchObjectSymRef = symRefTab()->findOrCreateExcpSymbolRef();
786
uint16_t i;
787
List<TR::Block> clonedCatchBlocks(comp()->trMemory());
788
789
for (auto handlerInfoIter = _tryCatchInfo.begin(); handlerInfoIter != _tryCatchInfo.end(); ++handlerInfoIter)
790
{
791
TryCatchInfo & handlerInfo = *handlerInfoIter;
792
uint16_t firstIndex = handlerInfo._handlerIndex;
793
794
// Two exception data entries can have ranges pointing at the same handler.
795
// If the types are different then we have to clone the handler.
796
797
//
798
//Partial Inlining - Deal with exception Handlers
799
//
800
if(_blocksToInline && !_blocksToInline->isInExceptionList(firstIndex)) //Case 1: item is not in exception list, therefore no ilgen to be done on it
801
{
802
continue; // nothing to be done for this handler!
803
}
804
else if (
805
_blocksToInline
806
&& _blocksToInline->isInExceptionList(firstIndex)
807
&& !_blocksToInline->isInList(firstIndex)
808
&& !isGenerated(firstIndex)) //Case 2: item is in exception list, but not in list of blocks to be ilgen'd
809
{
810
_blocksToInline->hasGeneratedRestartTree() ? genGotoPartialInliningCallBack(firstIndex,_blocksToInline->getGeneratedRestartTree()) :
811
_blocksToInline->setGeneratedRestartTree(genPartialInliningCallBack(firstIndex,_blocksToInline->getCallNodeTreeTop()));
812
handlerInfo._lastBlock = blocks(firstIndex);
813
handlerInfo._firstBlock = blocks(firstIndex);
814
handlerInfo._catchBlock = blocks(firstIndex);
815
816
blocks(firstIndex)->setIsAdded();
817
if(blocks(firstIndex) != _blocksToInline->getGeneratedRestartTree()->getEnclosingBlock())
818
{
819
lastBlock->getExit()->join(blocks(firstIndex)->getEntry());
820
cfg()->addNode(blocks(firstIndex));
821
cfg()->addEdge(blocks(firstIndex),_blocksToInline->getGeneratedRestartTree()->getEnclosingBlock());
822
}
823
else
824
{
825
lastBlock->getExit()->join(blocks(firstIndex)->getEntry());
826
cfg()->insertBefore(blocks(firstIndex),cfg()->getEnd()->asBlock());
827
}
828
lastBlock=handlerInfo._lastBlock;
829
//ok what I'm trying here is saying that my first block, last block and catchblock in my catcher are all the same (the one block)
830
831
handlerInfo._catchBlock->setHandlerInfo(handlerInfo._catchType, (uint8_t)comp()->getInlineDepth(), handlerInfoIter - _tryCatchInfo.begin(), method(), comp());
832
continue;
833
}
834
835
836
bool generateNewBlock = true;
837
TR::Block * handlerBlockFromNonExceptionControlFlow = 0;
838
if (isGenerated(firstIndex))
839
{
840
generateNewBlock = false;
841
TryCatchInfo * dupHandler = 0;
842
for (int32_t j = 0; j < (handlerInfoIter - _tryCatchInfo.begin()); ++j)
843
{
844
TryCatchInfo & h = _tryCatchInfo[j];
845
if (h._handlerIndex == firstIndex)
846
{
847
if (!dupHandler)
848
dupHandler = &h;
849
if (h._catchType == handlerInfo._catchType)
850
{
851
dupHandler = &h;
852
break;
853
}
854
}
855
}
856
857
if (!dupHandler)
858
{
859
handlerBlockFromNonExceptionControlFlow = _blocks[firstIndex];
860
generateNewBlock = true;
861
862
// this handler must also be reachable from the mainline code....we don't
863
// know how to handle this yet
864
// todo: figure out how to handle this.
865
//
866
// TR_ASSERT(dupHandler, "can't figure out why the handler is already generated");
867
// comp()->failCompilation<TR::CompilationException>("can't figure out why the handler is already generated");
868
}
869
870
if (!generateNewBlock)
871
{
872
if (handlerInfo._catchType != dupHandler->_catchType)
873
{
874
lastBlock = cloneHandler(&handlerInfo, dupHandler->_firstBlock, dupHandler->_lastBlock, lastBlock, &clonedCatchBlocks);
875
/*
876
TR_BlockCloner cloner(cfg());
877
handlerInfo->_firstBlock = cloner.cloneBlocks(dupHandler->_firstBlock, dupHandler->_lastBlock);
878
lastBlock->getExit()->join(handlerInfo->_firstBlock->getEntry());
879
handlerInfo->_lastBlock = lastBlock = cloner.getLastClonedBlock();
880
handlerInfo->_catchBlock = cloner.getToBlock(blocks(firstIndex));
881
cfg()->addSuccessorEdges(lastBlock);
882
*/
883
}
884
else
885
handlerInfo._catchBlock = dupHandler->_catchBlock;
886
}
887
}
888
889
if (generateNewBlock)
890
{
891
setupBBStartContext(firstIndex);
892
893
TR::SymbolReference *exceptionLoadSymRef = NULL;
894
if (handlerBlockFromNonExceptionControlFlow &&
895
_stack->topIndex() == 0)
896
{
897
TR::Node *exceptionLoadOnStack = _stack->top();
898
if (exceptionLoadOnStack->getOpCode().isLoadVarDirect() &&
899
exceptionLoadOnStack->getOpCode().hasSymbolReference() &&
900
exceptionLoadOnStack->getSymbolReference()->getSymbol()->isAutoOrParm())
901
{
902
exceptionLoadSymRef = exceptionLoadOnStack->getSymbolReference();
903
//dumpOptDetails("exc load on stack = %p\n", exceptionLoadOnStack);
904
}
905
}
906
907
_bcIndex = firstIndex;
908
909
// The stack at the start of a catch block only contains the catch object
910
loadSymbol(TR::aload, catchObjectSymRef);
911
if (_compilation->getHCRMode() == TR::osr || _compilation->getOSRMode() == TR::involuntaryOSR)
912
{
913
genTreeTop(TR::Node::createWithSymRef(_block->getEntry()->getNode(), TR::asynccheck, 0,
914
symRefTab()->findOrCreateAsyncCheckSymbolRef(_methodSymbol)));
915
916
// Under NextGenHCR, the commoned catch object will now be on the stack. This results
917
// in the addition of an unneeded temp if the block is split here. Short cut this by
918
// uncommoning them.
919
if (_compilation->getHCRMode() == TR::osr)
920
{
921
pop();
922
loadSymbol(TR::aload, catchObjectSymRef);
923
}
924
}
925
926
/*
927
* Spill the exception object into a temporary if it isn't immediately done so
928
* in the catch block. This is necessary because the exception object will not
929
* be preserved across method calls (and for a handful of other reasons) and
930
* cannot be materialized from the metadata. A stack temp is necessary in this
931
* case.
932
*/
933
uint8_t firstOpCode = _code[_bcIndex];
934
int32_t bc = convertOpCodeToByteCodeEnum(firstOpCode);
935
936
if (bc != J9BCastore)
937
{
938
TR::SymbolReference *exceptionObjectSymRef = symRefTab()->createTemporary(_methodSymbol, TR::Address);
939
TR::Node *exceptionNode = pop();
940
genTreeTop(TR::Node::createStore(exceptionObjectSymRef, exceptionNode));
941
loadConstant(TR::aconst, (void *)0);
942
genTreeTop(TR::Node::createStore(exceptionNode->getSymbolReference(), pop()));
943
loadSymbol(TR::aload, exceptionObjectSymRef);
944
if (trace)
945
traceMsg(comp(), "catch block first BC is not an astore, inserting explicit store of exception object\n");
946
}
947
948
TR::Node *node = _stack->top();
949
node->setIsNonNull(true);
950
951
TR::TreeTop *storeTree = NULL;
952
if (handlerBlockFromNonExceptionControlFlow)
953
{
954
if (!exceptionLoadSymRef)
955
{
956
comp()->failCompilation<TR::ILGenFailure>("Aborting at generate exception handlers");
957
}
958
else
959
{
960
TR::Node *storeNode = TR::Node::createStore(exceptionLoadSymRef, pop());
961
storeTree = TR::TreeTop::create(comp(), storeNode);
962
}
963
964
TR::Node *lastNode = handlerBlockFromNonExceptionControlFlow->getLastRealTreeTop()->getNode();
965
if (lastNode->getOpCode().isResolveOrNullCheck() ||
966
(lastNode->getOpCodeValue() == TR::treetop))
967
lastNode = lastNode->getFirstChild();
968
969
//traceMsg(comp(), "last node %p bc index %d and opcode %s\n", lastNode, lastNode->getByteCodeIndex(), lastNode->getOpCode().getName());
970
971
TR::ILOpCode &lastOpCode = lastNode->getOpCode();
972
if (!lastOpCode.isGoto() &&
973
!lastOpCode.isReturn() &&
974
(lastOpCode.getOpCodeValue() != TR::athrow))
975
{
976
comp()->failCompilation<TR::ILGenFailure>("Aborting: not goto, not return and not a throw.");
977
}
978
}
979
980
if (handlerBlockFromNonExceptionControlFlow)
981
{
982
lastBlock = cloneHandler(&handlerInfo, handlerBlockFromNonExceptionControlFlow, handlerBlockFromNonExceptionControlFlow, lastBlock, &clonedCatchBlocks);
983
lastBlock->prepend(storeTree);
984
}
985
else
986
{
987
handlerInfo._lastBlock = walker(lastBlock);
988
handlerInfo._firstBlock = lastBlock->getNextBlock();
989
handlerInfo._catchBlock = blocks(firstIndex);
990
lastBlock = handlerInfo._lastBlock;
991
}
992
}
993
994
handlerInfo._catchBlock->setHandlerInfo(handlerInfo._catchType, (uint8_t)comp()->getInlineDepth(), handlerInfoIter - _tryCatchInfo.begin(), method(), comp());
995
}
996
997
for (auto handlerInfoIter = _tryCatchInfo.begin(); handlerInfoIter != _tryCatchInfo.end(); ++handlerInfoIter)
998
{
999
TryCatchInfo & handlerInfo = *handlerInfoIter;
1000
if(_blocksToInline && !_blocksToInline->isInExceptionList(handlerInfo._handlerIndex)) //Case 1: item is not in exception list, therefore no ilgen to be done on it
1001
{
1002
continue; // nothing to be done for this handler!
1003
}
1004
TR::Block *catchBlock = handlerInfo._catchBlock;
1005
TR::Block *restartBlock = _blocksToInline? _blocksToInline->getGeneratedRestartTree()->getEnclosingBlock() : NULL;
1006
uint8_t precedingOpcode = _code[handlerInfo._startIndex-1];
1007
TR_J9ByteCode precedingBytecode = convertOpCodeToByteCodeEnum(precedingOpcode);
1008
uint8_t lastOpcode = _code[handlerInfo._endIndex];
1009
TR_J9ByteCode lastBytecode = convertOpCodeToByteCodeEnum(lastOpcode);
1010
bool isSynchronizedRegion = (precedingBytecode == J9BCmonitorenter && lastBytecode == J9BCmonitorexit);
1011
if (isSynchronizedRegion) // monitorenter preceding try region that ends in monitorexit means synchronized
1012
catchBlock->setIsSynchronizedHandler();
1013
1014
for (uint16_t j = handlerInfo._startIndex; j <= handlerInfo._endIndex; ++j)
1015
if (blocks(j) && cfg()->getNodes().find(blocks(j)))
1016
{
1017
if (blocks(j) == catchBlock)
1018
{
1019
_methodSymbol->setMayHaveNestedLoops(true);
1020
}
1021
1022
if (blocks(j) != restartBlock)
1023
{
1024
cfg()->addExceptionEdge(blocks(j), catchBlock);
1025
ListIterator<TR::Block> clonedIt(&clonedCatchBlocks);
1026
for (TR::Block * cb = clonedIt.getFirst(); cb; cb = clonedIt.getNext())
1027
{
1028
if (cb->getEntry()->getNode()->getByteCodeIndex() == j)
1029
cfg()->addExceptionEdge(cb, catchBlock);
1030
}
1031
}
1032
}
1033
}
1034
1035
_inExceptionHandler = false;
1036
return lastBlock;
1037
}
1038
1039
TR::Node *
1040
TR_J9ByteCodeIlGenerator::genMethodEnterHook()
1041
{
1042
if (method()->isStatic())
1043
return TR::Node::createWithSymRef(TR::MethodEnterHook, 0, symRefTab()->findOrCreateReportStaticMethodEnterSymbolRef(_methodSymbol));
1044
1045
loadAuto(TR::Address, 0);
1046
return TR::Node::createWithSymRef(TR::MethodEnterHook, 1, 1, pop(), symRefTab()->findOrCreateReportMethodEnterSymbolRef(_methodSymbol));
1047
}
1048
1049
void
1050
TR_J9ByteCodeIlGenerator::prependEntryCode(TR::Block * firstBlock)
1051
{
1052
bool trace = comp()->getOption(TR_TraceILGen);
1053
TR::Node * monitorEnter = 0;
1054
TR::Node * syncObjectStore = 0;
1055
TR::Node * thisObjectStore = 0;
1056
TR::TreeTop * nhrttCheckTree1 = 0, * nhrttCheckTree2 = 0, * nhrttCheckTree3 = 0, * nhrttCheckTree4 = 0;
1057
TR::Node * lockObject = 0;
1058
if (_methodSymbol->isSynchronised())
1059
{
1060
loadMonitorArg();
1061
1062
TR::Node * firstChild = pop();
1063
TR::SymbolReference * monEnterSymRef = symRefTab()->findOrCreateMethodMonitorEntrySymbolRef(_methodSymbol);
1064
1065
if (firstChild->getOpCodeValue() == TR::loadaddr && firstChild->getSymbol()->isClassObject())
1066
{
1067
monitorEnter = TR::Node::createWithSymRef(TR::aloadi, 1, 1, firstChild, symRefTab()->findOrCreateJavaLangClassFromClassSymbolRef());
1068
monitorEnter = TR::Node::createWithSymRef(TR::monent, 1, 1, monitorEnter, monEnterSymRef);
1069
}
1070
else
1071
{
1072
monitorEnter = TR::Node::createWithSymRef(TR::monent, 1, 1, firstChild, monEnterSymRef);
1073
}
1074
1075
monitorEnter->setSyncMethodMonitor(true);
1076
TR_OpaqueClassBlock * owningClass = _methodSymbol->getResolvedMethod()->containingClass();
1077
if (owningClass != comp()->getObjectClassPointer())
1078
{
1079
monitorEnter->setSecond((TR::Node*)owningClass);
1080
if (trace)
1081
traceMsg(comp(), "setting class for %p to be %p\n", monitorEnter, owningClass);
1082
}
1083
1084
_methodSymbol->setMayContainMonitors(true);
1085
1086
if (_methodSymbol->isStatic())
1087
monitorEnter->setStaticMonitor(true);
1088
1089
// Store the receiver object to a temporary to deal with the case where the bytecode has been hacked
1090
// to write to the receiver. The temporary will be used on the monitor exit
1091
//
1092
if (_methodSymbol->getSyncObjectTemp())
1093
{
1094
if (_methodSymbol->isStatic())
1095
loadSymbol(TR::loadaddr, symRefTab()->findOrCreateClassSymbol(_methodSymbol, 0, method()->containingClass()));
1096
else
1097
loadAuto(TR::Address, 0);
1098
1099
lockObject = pop();
1100
if (monitorEnter->getFirstChild()->getOpCodeValue() == TR::aloadi &&
1101
monitorEnter->getFirstChild()->getSymbolReference() == symRefTab()->findJavaLangClassFromClassSymbolRef())
1102
lockObject = monitorEnter->getFirstChild();
1103
syncObjectStore = TR::Node::createStore(_methodSymbol->getSyncObjectTemp(), lockObject);
1104
}
1105
}
1106
1107
// if the receiver of Object.<init> has been written into, then we need to save a copy of the receiver into
1108
// a temporary and use that in the call to the finalizer
1109
//
1110
if (_methodSymbol->getThisTempForObjectCtor())
1111
{
1112
loadAuto(TR::Address, 0);
1113
thisObjectStore = TR::Node::createStore(_methodSymbol->getThisTempForObjectCtor(), pop());
1114
}
1115
1116
TR::Node * methodEnterHook = 0;
1117
1118
static const char* disableMethodHookForCallees = feGetEnv("TR_DisableMethodHookForCallees");
1119
if ((fej9()->isMethodTracingEnabled(_methodSymbol->getResolvedMethod()->getPersistentIdentifier())
1120
|| (!comp()->getOption(TR_FullSpeedDebug)
1121
&& TR::Compiler->vm.canMethodEnterEventBeHooked(comp())))
1122
&& (isOutermostMethod() || !disableMethodHookForCallees))
1123
{
1124
methodEnterHook = genMethodEnterHook();
1125
}
1126
1127
if (methodEnterHook || monitorEnter)
1128
{
1129
// If there's a branch to the first byte code then we have to prepend
1130
// the monitor enter and/or entry hook into its own block
1131
//
1132
if ((firstBlock->getPredecessors().size() > 1) || !isOutermostMethod())
1133
firstBlock = _methodSymbol->prependEmptyFirstBlock();
1134
1135
if (methodEnterHook)
1136
firstBlock->prepend(TR::TreeTop::create(comp(), methodEnterHook));
1137
1138
TR::TreeTop *syncObjectTT = NULL;
1139
if (syncObjectStore)
1140
syncObjectTT = TR::TreeTop::create(comp(), syncObjectStore);
1141
1142
if (monitorEnter)
1143
firstBlock->prepend(TR::TreeTop::create(comp(), monitorEnter));
1144
1145
if (nhrttCheckTree3)
1146
firstBlock->prepend(nhrttCheckTree3);
1147
1148
if (nhrttCheckTree2)
1149
firstBlock->prepend(nhrttCheckTree2);
1150
1151
if (nhrttCheckTree1)
1152
firstBlock->prepend(nhrttCheckTree1);
1153
1154
// the sync object store must be the first thing here, or everything above it will load a bad object reference
1155
if (syncObjectTT)
1156
firstBlock->prepend(syncObjectTT);
1157
}
1158
1159
if (thisObjectStore)
1160
{
1161
if (nhrttCheckTree4)
1162
firstBlock->prepend(nhrttCheckTree4);
1163
firstBlock->prepend(TR::TreeTop::create(comp(), thisObjectStore));
1164
}
1165
1166
if (comp()->isDLT() && isOutermostMethod())
1167
{
1168
genDLTransfer(firstBlock);
1169
}
1170
}
1171
1172
void
1173
TR_J9ByteCodeIlGenerator::prependGuardedCountForRecompilation(TR::Block * originalFirstBlock)
1174
{
1175
//
1176
// guardBlock: if (!countForRecompile) goto originalFirstBlock;
1177
// bumpCounterBlock: bodyInfo->count--;
1178
// if (bodyInfo->count > 0) goto originalFirstBlock;
1179
// callRecompileBlock: call jitRetranslateCallerWithPreparation(j9method, startPC);
1180
// bodyInfo->count=10000
1181
// originalFirstBlock: ...
1182
//
1183
1184
bool trace = comp()->getOption(TR_TraceILGen);
1185
TR::TreeTop *originalFirstTree = _methodSymbol->getFirstTreeTop();
1186
TR::Node *node=originalFirstTree->getNode();
1187
1188
// construct guard
1189
TR::Block *guardBlock = TR::Block::createEmptyBlock(comp());
1190
TR::Node *cmpFlagNode;
1191
if (comp()->getOption(TR_ImmediateCountingRecompilation))
1192
{
1193
cmpFlagNode = TR::Node::createif(TR::ificmpeq, TR::Node::iconst(1234), TR::Node::iconst(5678), originalFirstBlock->getEntry());
1194
}
1195
else
1196
{
1197
TR::Node *loadFlagNode = TR::Node::createWithSymRef(node, TR::iload, 0, comp()->getSymRefTab()->findOrCreateCountForRecompileSymbolRef());
1198
1199
if (comp()->getOption(TR_EnableGCRPatching))
1200
cmpFlagNode = TR::Node::createif(TR::ificmpne, loadFlagNode, TR::Node::create(node, TR::iconst, 0, 1), originalFirstBlock->getEntry());
1201
else
1202
cmpFlagNode = TR::Node::createif(TR::ificmpeq, loadFlagNode, TR::Node::create(node, TR::iconst, 0, 0), originalFirstBlock->getEntry());
1203
}
1204
TR::TreeTop *cmpFlag = TR::TreeTop::create(comp(), cmpFlagNode);
1205
guardBlock->append(cmpFlag);
1206
TR::DebugCounter::prependDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "gcrMethods/byJittedBody/(%s)", comp()->signature()), cmpFlag, 1, TR::DebugCounter::Moderate);
1207
1208
1209
// construct counter bump
1210
TR::Block *bumpCounterBlock = TR::Block::createEmptyBlock(comp());
1211
TR::TreeTop * treeTop = TR::TreeTop::createIncTree(comp(), node, comp()->getRecompilationInfo()->getCounterSymRef(),
1212
-comp()->getOptions()->getGCRDecCount(), NULL, true);
1213
bumpCounterBlock->append(treeTop);
1214
TR::DebugCounter::prependDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "gcrCounterBumps/byJittedBody/(%s)", comp()->signature()), treeTop, 1, TR::DebugCounter::Free);
1215
TR::Node *bumpNode = treeTop->getNode()->getNumChildren() > 1 ? treeTop->getNode()->getSecondChild() : treeTop->getNode()->getFirstChild();
1216
1217
TR::Node *cmpCountNode = TR::Node::createif(TR::ificmpgt, bumpNode, TR::Node::create(TR::iconst, 0, 0), originalFirstBlock->getEntry());
1218
bumpCounterBlock->append(TR::TreeTop::create(comp(), cmpCountNode));
1219
bumpCounterBlock->setIsCold(true);
1220
bumpCounterBlock->setFrequency(UNKNOWN_COLD_BLOCK_COUNT);
1221
1222
1223
// construct call block
1224
TR::Block *callRecompileBlock = TR::Block::createEmptyBlock(comp());
1225
callRecompileBlock->append(TR::TreeTop::createResetTree(comp(), node, comp()->getRecompilationInfo()->getCounterSymRef(),
1226
comp()->getOptions()->getGCRResetCount(), NULL, true));
1227
1228
// Create the instruction that will patch my cmp
1229
if (comp()->getOption(TR_EnableGCRPatching))
1230
{
1231
TR::Node *constNode = TR::Node::create(node, TR::bconst, 0);
1232
constNode->setByte(2);
1233
callRecompileBlock->append(TR::TreeTop::create(comp(), TR::Node::createWithSymRef(TR::bstore, 1, 1, constNode,
1234
comp()->getSymRefTab()->findOrCreateGCRPatchPointSymbolRef())));
1235
}
1236
1237
TR::TreeTop *callTree = TR::TransformUtil::generateRetranslateCallerWithPrepTrees(node, TR_PersistentMethodInfo::RecompDueToGCR, comp());
1238
callRecompileBlock->append(callTree);
1239
callRecompileBlock->setIsCold(true);
1240
callRecompileBlock->setFrequency(UNKNOWN_COLD_BLOCK_COUNT);
1241
1242
// get all the blocks into the CFG
1243
if (trace) traceMsg(comp(), "adding edge start to guard\n");
1244
cfg()->addEdge(cfg()->getStart(), guardBlock);
1245
1246
if (trace) traceMsg(comp(), "insert before guard to bump\n");
1247
cfg()->insertBefore(guardBlock, bumpCounterBlock);
1248
if (trace) traceMsg(comp(), "insert before bump to call\n");
1249
cfg()->insertBefore(bumpCounterBlock, callRecompileBlock);
1250
if (trace) traceMsg(comp(), "insertbefore call to original\n");
1251
cfg()->insertBefore(callRecompileBlock, originalFirstBlock);
1252
1253
if (trace) traceMsg(comp(), "remove start to original\n");
1254
cfg()->removeEdge(cfg()->getStart(), originalFirstBlock);
1255
if (trace) traceMsg(comp(), "set first\n");
1256
_methodSymbol->setFirstTreeTop(guardBlock->getEntry());
1257
1258
comp()->getRecompilationInfo()->getJittedBodyInfo()->setUsesGCR();
1259
}
1260
1261
void
1262
TR_J9ByteCodeIlGenerator::createGeneratedFirstBlock()
1263
{
1264
_block = TR::Block::createEmptyBlock(comp());
1265
cfg()->addNode(_block);
1266
cfg()->addEdge(cfg()->getStart(), _block);
1267
cfg()->addEdge(_block, cfg()->getEnd());
1268
_methodSymbol->setFirstTreeTop(_block->getEntry());
1269
}
1270
1271
bool
1272
TR_J9ByteCodeIlGenerator::hasFPU()
1273
{
1274
bool result = !comp()->getOption(TR_DisableFPCodeGen) ? comp()->target().cpu.hasFPU() : false;
1275
return result;
1276
}
1277
1278
1279
bool
1280
TR_J9ByteCodeIlGenerator::genJNIIL()
1281
{
1282
if (!cg()->getSupportsDirectJNICalls() || comp()->getOption(TR_DisableDirectToJNI) || (comp()->compileRelocatableCode() && !cg()->supportsDirectJNICallsForAOT()))
1283
return false;
1284
1285
// A JNI thunk method cannot call back to the slow path, as would occur in the following case
1286
if (method()->numberOfParameterSlots() > J9_INLINE_JNI_MAX_ARG_COUNT && comp()->cg()->hasFixedFrameC_CallingConvention())
1287
return false;
1288
1289
if (_methodSymbol->getRecognizedMethod() == TR::sun_misc_Unsafe_ensureClassInitialized)
1290
{
1291
return false;
1292
}
1293
1294
1295
bool HasFPU = hasFPU();
1296
#if defined(__ARM_PCS_VFP)
1297
HasFPU = false;
1298
#endif
1299
1300
if (!HasFPU && (method()->returnOpCode() == TR::freturn || method()->returnOpCode() == TR::dreturn))
1301
return false;
1302
1303
if (!HasFPU)
1304
{
1305
for (uint32_t i = 0; i < method()->numberOfParameterSlots(); ++i)
1306
{
1307
if (method()->parmType(i) == TR::Float || method()->parmType(i) == TR::Double)
1308
return false;
1309
}
1310
}
1311
1312
if (debug("traceInfo"))
1313
diagnostic("Compiling JNI virtual thunk for %s.\n", method()->signature(trMemory()));
1314
1315
createGeneratedFirstBlock();
1316
1317
_methodSymbol->setJNI();
1318
1319
ListIterator<TR::ParameterSymbol> parms(&_methodSymbol->getParameterList());
1320
for (TR::ParameterSymbol * p = parms.getFirst(); p; p = parms.getNext())
1321
loadAuto(p->getDataType(), p->getSlot());
1322
1323
TR::MethodSymbol::Kinds callKind = method()->isStatic() ? TR::MethodSymbol::Static : TR::MethodSymbol::Virtual;
1324
1325
TR::SymbolReference * callSymRef =
1326
symRefTab()->findOrCreateMethodSymbol(_methodSymbol->getResolvedMethodIndex(), -1, method(), callKind);
1327
1328
genInvokeDirect(callSymRef);
1329
1330
bool genMonitors = _methodSymbol->isSynchronised();
1331
1332
genReturn(method()->returnOpCode(), genMonitors);
1333
1334
prependEntryCode(_block);
1335
1336
return true;
1337
}
1338
1339
void
1340
TR_J9ByteCodeIlGenerator::genHWOptimizedStrProcessingAvailable()
1341
{
1342
static int32_t constToLoad = -1;
1343
initialize();
1344
int32_t firstIndex = _bcIndex;
1345
setIsGenerated(_bcIndex);
1346
if (constToLoad == -1)
1347
{
1348
if (cg()->getSupportsInlineStringCaseConversion())
1349
constToLoad = 1;
1350
else
1351
constToLoad = 0;
1352
}
1353
1354
loadConstant(TR::iconst, constToLoad);
1355
1356
setIsGenerated(++_bcIndex);
1357
_bcIndex = genReturn(method()->returnOpCode(), method()->isSynchronized());
1358
TR::Block * block = blocks(firstIndex);
1359
cfg()->addEdge(cfg()->getStart(), block);
1360
block->setVisitCount(_blockAddedVisitCount);
1361
block->getExit()->getNode()->copyByteCodeInfo(block->getLastRealTreeTop()->getNode());
1362
cfg()->insertBefore(block, 0);
1363
_bcIndex = 0;
1364
_methodSymbol->setFirstTreeTop(blocks(0)->getEntry());
1365
prependEntryCode(blocks(0));
1366
1367
dumpOptDetails(comp(), "\tOverriding default return value with %d.\n", constToLoad);
1368
}
1369
1370
void
1371
TR_J9ByteCodeIlGenerator::genJITIntrinsicsEnabled()
1372
{
1373
bool isZLinux = comp()->target().cpu.isZ() && comp()->target().isLinux();
1374
1375
static int32_t constToLoad = (comp()->target().isZOS() || isZLinux) &&
1376
!comp()->getOption(TR_DisablePackedDecimalIntrinsics) ? 1 : 0;
1377
1378
initialize();
1379
int32_t firstIndex = _bcIndex;
1380
setIsGenerated(_bcIndex);
1381
1382
loadConstant(TR::iconst, constToLoad);
1383
1384
setIsGenerated(++_bcIndex);
1385
_bcIndex = genReturn(method()->returnOpCode(), method()->isSynchronized());
1386
TR::Block * block = blocks(firstIndex);
1387
cfg()->addEdge(cfg()->getStart(), block);
1388
block->setVisitCount(_blockAddedVisitCount);
1389
block->getExit()->getNode()->copyByteCodeInfo(block->getLastRealTreeTop()->getNode());
1390
cfg()->insertBefore(block, 0);
1391
_bcIndex = 0;
1392
_methodSymbol->setFirstTreeTop(blocks(0)->getEntry());
1393
prependEntryCode(blocks(0));
1394
1395
dumpOptDetails(comp(), "\tOverriding default return value with %d.\n", constToLoad);
1396
}
1397
1398
void
1399
TR_J9ByteCodeIlGenerator::genIsORBDeepCopyAvailable()
1400
{
1401
static int32_t constToLoad = 1;
1402
initialize();
1403
int32_t firstIndex = _bcIndex;
1404
setIsGenerated(_bcIndex);
1405
1406
loadConstant(TR::iconst, constToLoad);
1407
1408
setIsGenerated(++_bcIndex);
1409
_bcIndex = genReturn(method()->returnOpCode(), method()->isSynchronized());
1410
TR::Block * block = blocks(firstIndex);
1411
cfg()->addEdge(cfg()->getStart(), block);
1412
block->setVisitCount(_blockAddedVisitCount);
1413
block->getExit()->getNode()->copyByteCodeInfo(block->getLastRealTreeTop()->getNode());
1414
cfg()->insertBefore(block, 0);
1415
_bcIndex = 0;
1416
_methodSymbol->setFirstTreeTop(blocks(0)->getEntry());
1417
prependEntryCode(blocks(0));
1418
1419
dumpOptDetails(comp(), "\tOverriding default return value with %d.\n", constToLoad);
1420
}
1421
1422
1423
void
1424
TR_J9ByteCodeIlGenerator::genJavaLangSystemIdentityHashCode()
1425
{
1426
TR::Block * ifBlock, * return0Block, * computeBlock;
1427
1428
//printf("Transforming TR::java_lang_System_identityHashCode in %s\n", comp()->signature());
1429
1430
// the object parameter
1431
ListIterator<TR::ParameterSymbol> parms(&_methodSymbol->getParameterList());
1432
TR::ParameterSymbol * p = parms.getFirst();
1433
TR::Node * objectRef = TR::Node::createLoad(symRefTab()->findOrCreateAutoSymbol(_methodSymbol, p->getSlot(), p->getDataType()));
1434
1435
// ifblock
1436
_block = ifBlock = TR::Block::createEmptyBlock(comp());
1437
_methodSymbol->setFirstTreeTop(ifBlock->getEntry());
1438
1439
loadAuto(p->getDataType(),p->getSlot());
1440
loadConstant(TR::aconst, 0);
1441
TR::Node * second = pop();
1442
TR::Node * first = pop();
1443
1444
computeBlock = TR::Block::createEmptyBlock(comp());
1445
1446
genTreeTop(TR::Node::createif(TR::ifacmpne, first, second, computeBlock->getEntry()));
1447
1448
// return0 block
1449
_block = return0Block = TR::Block::createEmptyBlock(comp());
1450
loadConstant(TR::iconst, 0);
1451
genTreeTop(TR::Node::create(method()->returnOpCode(), 1, pop()));
1452
1453
// compute block
1454
_block = computeBlock;
1455
1456
TR::Node *objHeaderFlagsField;
1457
TR::Node *opNode;
1458
TR::Node *constNode;
1459
TR::Node *shlNode;
1460
TR::Node *orNode;
1461
TR::SymbolReferenceTable *symRefTab = comp()->getSymRefTab();
1462
1463
// object header flags now occupy 4bytes (instead of 8) on 64-bit
1464
//
1465
objHeaderFlagsField = TR::Node::createWithSymRef(TR::iloadi, 1, 1, objectRef,
1466
symRefTab->findOrCreateHeaderFlagsSymbolRef());
1467
opNode = TR::Node::create(TR::ishr, 2, objHeaderFlagsField, TR::Node::create(objHeaderFlagsField,
1468
TR::iconst, 0, 16));
1469
1470
opNode = TR::Node::create(TR::iand, 2, opNode, TR::Node::create(opNode, TR::iconst, 0, 32767));
1471
shlNode = TR::Node::create(TR::ishl, 2, opNode, TR::Node::create(opNode, TR::iconst, 0, 16));
1472
1473
orNode = TR::Node::create(TR::ior, 2, opNode, shlNode);
1474
1475
TR::Node *trTreeTopNode = TR::Node::create(TR::treetop, 1, orNode);
1476
1477
computeBlock->append(TR::TreeTop::create(comp(), trTreeTopNode));
1478
1479
push(orNode);
1480
genTreeTop(TR::Node::create(method()->returnOpCode(), 1, pop()));
1481
1482
cfg()->addEdge(cfg()->getStart(), ifBlock);
1483
1484
cfg()->insertBefore(ifBlock, return0Block);
1485
cfg()->insertBefore(return0Block, computeBlock);
1486
cfg()->insertBefore(computeBlock, 0);
1487
}
1488
1489
bool
1490
TR_J9ByteCodeIlGenerator::genNewInstanceImplThunk()
1491
{
1492
// Answers a new instance of the class represented by the
1493
// receiver, created by invoking the default (i.e. zero-argument)
1494
// constructor. If there is no such constructor, or if the
1495
// creation fails (either because of a lack of available memory or
1496
// because an exception is thrown by the constructor), an
1497
// InstantiationException is thrown. If the default constructor
1498
// exists, but is not accessible from the context where this
1499
// message is sent, an IllegalAccessException is thrown.
1500
//
1501
if (debug("traceInfo"))
1502
diagnostic("Compiling newInstanceImpl thunk: %s.\n", method()->signature(trMemory()));
1503
1504
if (comp()->getRecompilationInfo())
1505
{
1506
comp()->getRecompilationInfo()->preventRecompilation();
1507
1508
// Disable Sampling
1509
TR_PersistentJittedBodyInfo *bodyInfo = comp()->getRecompilationInfo()->getJittedBodyInfo();
1510
if (bodyInfo)
1511
bodyInfo->setDisableSampling(true);
1512
}
1513
1514
TR_OpaqueClassBlock *classId = method()->classOfMethod(); // will never be java.lang.Class (unless we are in a hacky world, e.g. JarTester?)
1515
1516
TR_ResolvedMethod *ctor = fej9()->getDefaultConstructor(trMemory(), classId);
1517
if (!ctor || TR::Compiler->cls.isAbstractClass(comp(), classId)) return false;
1518
1519
TR::Block * firstBlock, * initBlock, * catchAllBlock;
1520
1521
_block = firstBlock = TR::Block::createEmptyBlock(comp());
1522
cfg()->addEdge(cfg()->getStart(), firstBlock);
1523
_methodSymbol->setFirstTreeTop(firstBlock->getEntry());
1524
1525
ListIterator<TR::ParameterSymbol> parms(&_methodSymbol->getParameterList());
1526
TR::ParameterSymbol *p0 = parms.getFirst();// this class
1527
TR::ParameterSymbol *p1 = parms.getNext(); // caller class
1528
1529
// HACK HACK HACK
1530
p0->setReferencedParameter();
1531
1532
if (!((TR_J9VM *)fej9())->isPublicClass(classId) || !ctor->isPublic())
1533
{
1534
TR::SymbolReference * accessCheckSymRef =
1535
symRefTab()->findOrCreateRuntimeHelper(TR_newInstanceImplAccessCheck, true, true, true);
1536
1537
loadConstant(TR::aconst, ctor->getPersistentIdentifier()); // Nullary Constructor's identifier
1538
loadAuto(p1->getDataType(), p1->getSlot()); // Caller Class
1539
//the call to findOrCreateClassSymbol is safe even though we pass CPI of -1 since it is guarded by !isAOT check in createResolvedMethodWithSignature
1540
loadSymbol(TR::loadaddr, symRefTab()->findOrCreateClassSymbol(_methodSymbol, -1, classId)); // This Class
1541
1542
TR::Node* node = pop();
1543
node = TR::Node::createWithSymRef(TR::aloadi, 1, 1, node, symRefTab()->findOrCreateJavaLangClassFromClassSymbolRef());
1544
push(node);
1545
1546
genTreeTop(genNodeAndPopChildren(TR::call, 3, accessCheckSymRef));
1547
}
1548
//the call to findOrCreateClassSymbol is safe even though we pass CPI of -1 since it is guarded by !isAOT check in createResolvedMethodWithSignature
1549
loadSymbol(TR::loadaddr, symRefTab()->findOrCreateClassSymbol(_methodSymbol, -1, classId));
1550
genNew();
1551
TR::SymbolReference * tempSymRef = symRefTab()->findOrCreatePendingPushTemporary(_methodSymbol, 0, TR::Address);
1552
genTreeTop(TR::Node::createStore(tempSymRef, pop()));
1553
1554
_block = initBlock = TR::Block::createEmptyBlock(comp());
1555
1556
push(TR::Node::createLoad(tempSymRef));
1557
dup();
1558
genInvokeDirect(symRefTab()->findOrCreateMethodSymbol(JITTED_METHOD_INDEX, -1, ctor, TR::MethodSymbol::Special));
1559
_methodSymbol->setMayHaveInlineableCall(true);
1560
genTreeTop(TR::Node::create(method()->returnOpCode(), 1, pop()));
1561
1562
cfg()->insertBefore(firstBlock, initBlock);
1563
cfg()->insertBefore(initBlock, 0);
1564
1565
return true;
1566
}
1567
1568
TR::Node *
1569
TR_J9ByteCodeIlGenerator::genNewInstanceImplCall(TR::Node *classNode)
1570
{
1571
TR_ASSERT(_methodSymbol->getRecognizedMethod() == TR::java_lang_Class_newInstance,
1572
"should only be finding a call to newInstanceImpl from newInstance");
1573
TR_ResolvedMethod *caller = method()->owningMethod(); // the caller of Class.newInstance()
1574
TR_ASSERT(caller, "should only be transforming newInstanceImpl call if newInstance is being inlined");
1575
1576
TR::Node *classNodeAsClass = TR::Node::createWithSymRef(TR::aloadi, 1, 1, classNode, symRefTab()->findOrCreateClassFromJavaLangClassSymbolRef());
1577
//the call to findOrCreateClassSymbol is safe even though we pass CPI of -1 since we check for !compileRelocatableCode() in the caller
1578
TR::Node *node = TR::Node::createWithSymRef(TR::loadaddr, 0, symRefTab()->findOrCreateClassSymbol(_methodSymbol, -1, caller->classOfMethod()));
1579
TR::Node *nodeAsObject = TR::Node::createWithSymRef(TR::aloadi, 1, 1, node, symRefTab()->findOrCreateJavaLangClassFromClassSymbolRef());
1580
1581
TR::Node *callNode = TR::Node::createWithSymRef(TR::acalli, 3, 3,
1582
classNodeAsClass,
1583
classNode,
1584
nodeAsObject,
1585
symRefTab()->findOrCreateObjectNewInstanceImplSymbol(_methodSymbol));
1586
1587
return callNode;
1588
}
1589
1590
void
1591
TR_J9ByteCodeIlGenerator::genDLTransfer(TR::Block *firstBlock)
1592
{
1593
TR::Block *newFirstBlock;
1594
IndexPair *innermostPair = NULL, *outmostPair = NULL, *ip;
1595
TR::SymbolReference *dltSteerSymRef = NULL;
1596
TR::TreeTop *steerTarget, *storeDltSteer = NULL;
1597
int32_t dltBCIndex = comp()->getDltBcIndex(), nestedCnt = 0;
1598
1599
// if we've DLTed into a non-empty object constructor (an evil bytecode modifier may have caused this),
1600
// then we will be broken because the we have not initialized the temp slot to use in the
1601
// call to jitCheckIfFinalize. in most cases this should be a non-issue because we almost always
1602
// inline Object.<init>
1603
//
1604
if (_methodSymbol->getResolvedMethod()->isNonEmptyObjectConstructor())
1605
{
1606
comp()->failCompilation<TR::ILGenFailure>("DLT into a non-empty Object constructor");
1607
}
1608
1609
for (ip = _backwardBranches.getFirst(); ip; ip = ip->getNext())
1610
{
1611
if (ip->_toIndex>dltBCIndex || ip->_fromIndex<dltBCIndex)
1612
continue;
1613
nestedCnt++;
1614
if (innermostPair == NULL)
1615
innermostPair = ip;
1616
outmostPair = ip;
1617
}
1618
1619
// if we are not within loops or we start the only loop, we can jump to the particular bytecode directly
1620
if (nestedCnt>1 || (innermostPair!=NULL && dltBCIndex!=innermostPair->_toIndex))
1621
{
1622
dltSteerSymRef = symRefTab()->createTemporary(comp()->getMethodSymbol(), TR::Int32);
1623
1624
TR::Node *storeNode = TR::Node::createWithSymRef(TR::istore, 1, 1, TR::Node::create(TR::iconst, 0, 0), dltSteerSymRef);
1625
storeDltSteer = TR::TreeTop::create(comp(), storeNode);
1626
}
1627
1628
// usually we should be at block starting point, but deal with middle of block anyway
1629
if (_blocks[dltBCIndex] != NULL)
1630
{
1631
if (dltSteerSymRef != NULL)
1632
_blocks[dltBCIndex]->prepend(storeDltSteer);
1633
steerTarget = _blocks[dltBCIndex]->getEntry();
1634
}
1635
else
1636
{
1637
TR::Block *myBlock = NULL;
1638
for (int32_t i=dltBCIndex-1; i>=0 && (myBlock=_blocks[i])==NULL; i--)
1639
;
1640
TR_ASSERT(myBlock!=NULL, "Cannot find the block DLT point belongs to");
1641
1642
for (steerTarget=myBlock->getEntry(); steerTarget!=myBlock->getExit() && steerTarget->getNode()->getByteCodeIndex()!=dltBCIndex; steerTarget=steerTarget->getNextTreeTop())
1643
;
1644
TR_ASSERT(steerTarget->getNode()->getByteCodeIndex()==dltBCIndex, "Cannot find the treeTop DLT point belongs to");
1645
1646
if (steerTarget == myBlock->getEntry())
1647
{
1648
if (dltSteerSymRef != NULL)
1649
myBlock->prepend(storeDltSteer);
1650
}
1651
else
1652
{
1653
// FIXME: fixupCommoning or copyExceptionSuccessor need to be revisited
1654
myBlock = myBlock->split(steerTarget, cfg());
1655
if (dltSteerSymRef != NULL)
1656
myBlock->prepend(storeDltSteer);
1657
steerTarget = myBlock->getEntry();
1658
}
1659
}
1660
1661
TR::TreeTop **haveSeenTargets = (TR::TreeTop **)comp()->trMemory()->allocateMemory(sizeof(void *) * (nestedCnt+1), heapAlloc);
1662
haveSeenTargets[0] = steerTarget;
1663
int32_t haveSeenCount = 1;
1664
for (; innermostPair != NULL && innermostPair != outmostPair->getNext(); innermostPair = innermostPair->getNext())
1665
{
1666
if (innermostPair->_fromIndex < dltBCIndex || innermostPair->_toIndex > dltBCIndex)
1667
continue;
1668
TR::Block *loopStart = _blocks[innermostPair->_toIndex];
1669
TR::TreeTop *entryTP = loopStart->getEntry();
1670
int32_t seenIndex;
1671
1672
// Handle multiple loops having the same _toIndex
1673
for (seenIndex=0; seenIndex < haveSeenCount && entryTP != haveSeenTargets[seenIndex]; seenIndex++);
1674
if (seenIndex < haveSeenCount)
1675
continue;
1676
loopStart->split(entryTP->getNextTreeTop(), cfg());
1677
TR::Node *childNode = TR::Node::createWithSymRef(TR::iload, 0, dltSteerSymRef);
1678
TR::Node *constNode = TR::Node::create(TR::iconst, 0, 0);
1679
TR::Node *ifNode = TR::Node::createif(TR::ificmpne, childNode, constNode, steerTarget);
1680
loopStart->prepend(TR::TreeTop::create(comp(), ifNode));
1681
cfg()->addEdge(loopStart, steerTarget->getNode()->getBlock());
1682
steerTarget = entryTP;
1683
haveSeenTargets[haveSeenCount++] = steerTarget;
1684
}
1685
1686
// Transfer the data in
1687
comp()->setDltSlotDescription(fej9()->getCurrentLocalsMapForDLT(comp()));
1688
newFirstBlock = _methodSymbol->prependEmptyFirstBlock();
1689
1690
if (dltSteerSymRef != NULL)
1691
{
1692
TR::Node *storeNode = TR::Node::createWithSymRef(TR::istore, 1, 1, TR::Node::create(TR::iconst, 0, 1), dltSteerSymRef);
1693
storeDltSteer = TR::TreeTop::create(comp(), storeNode);
1694
newFirstBlock->append(storeDltSteer);
1695
}
1696
1697
bool isSyncMethod=_methodSymbol->isSynchronised(), isStaticMethod=_methodSymbol->isStatic();
1698
int32_t tempSlots = _method->numberOfTemps();
1699
int32_t parmSlots = _method->numberOfParameterSlots();
1700
int32_t *slotsDescription = comp()->getDltSlotDescription();
1701
int32_t parmIteratorIdx = 0;
1702
TR::SymbolReference *shadowSymRef = symRefTab()->findOrCreateGenericIntShadowSymbolReference(0);
1703
TR::Node *dltBufChild = NULL;
1704
1705
symRefTab()->aliasBuilder.gcSafePointSymRefNumbers().set(shadowSymRef->getReferenceNumber());
1706
1707
if (parmSlots != 0 || tempSlots != 0 || (isSyncMethod && !isStaticMethod))
1708
{
1709
int32_t fixedOffset;
1710
1711
dltBufChild = TR::Node::createWithSymRef(TR::loadaddr, 0, symRefTab()->findOrCreateDLTBlockSymbolRef());
1712
1713
fixedOffset = fej9()->getDLTBufferOffsetInBlock();
1714
if (comp()->target().is64Bit())
1715
{
1716
TR::Node *constNode = TR::Node::create(TR::lconst, 0);
1717
constNode->setLongInt(fixedOffset);
1718
dltBufChild = TR::Node::create(TR::aladd, 2, dltBufChild, constNode);
1719
}
1720
else
1721
dltBufChild = TR::Node::create(TR::aiadd, 2, dltBufChild, TR::Node::create(TR::iconst, 0, fixedOffset));
1722
dltBufChild = TR::Node::createWithSymRef(TR::aloadi, 1, 1, dltBufChild, shadowSymRef);
1723
}
1724
1725
if (isSyncMethod && !isStaticMethod)
1726
{
1727
int32_t *first32Slots = slotsDescription;
1728
TR::SymbolReference *syncObjectSymRef = _methodSymbol->getSyncObjectTemp();
1729
bool slot0Modified = (syncObjectSymRef!=NULL);
1730
bool slot0StillActive = (*first32Slots) & 1;
1731
1732
parmIteratorIdx = 1;
1733
1734
// We have 4 scenarios to deal with:
1735
// slot0StillActive: no matter if slot0Modified or not, we cannot touch slot0 itself.
1736
// By and large, these should account for the majority cases for DLT.
1737
// There is no difference from normal JIT in these cases;
1738
// For modified case, we need to refresh the syncObjectTemp;
1739
// slot0 not active and notModified either:
1740
// This is the most likely error scenario we can encounter. For exception
1741
// handling purpose, we have to reinstate slot0, and we cannot go wrong.
1742
// slot0 not active but modified:
1743
// We cannot do much about it until METADATA can carry the receiver info
1744
// back to the exception handler. For now, we just bail out of the compilation.
1745
//
1746
1747
if (!slot0StillActive && slot0Modified)
1748
{
1749
comp()->failCompilation<TR::ILGenFailure>("DLT on a tampered method, need better MetaData to deal with it");
1750
}
1751
1752
// the syncObjectTemp cannot be relied on anymore, since its store is by-passed
1753
// Copy the hidden slot to our syncObjectTemp
1754
//
1755
TR::Node *loadHiddenSlot = NULL;
1756
if (slot0Modified)
1757
{
1758
loadHiddenSlot = TR::Node::createWithSymRef(TR::aloadi, 1, 1, dltBufChild, shadowSymRef);
1759
1760
TR::Node *storeSyncObject = TR::Node::createWithSymRef(TR::astore, 1, 1, loadHiddenSlot, syncObjectSymRef);
1761
newFirstBlock->append(TR::TreeTop::create(comp(), storeSyncObject));
1762
}
1763
1764
if (!slot0StillActive && !slot0Modified)
1765
{
1766
List<TR::SymbolReference> &slot0list = _methodSymbol->getAutoSymRefs(0);
1767
ListIterator<TR::SymbolReference> s0i(&slot0list);
1768
TR::SymbolReference *slot0SymRef = s0i.getFirst();
1769
1770
TR_ASSERT(slot0list.isSingleton(), "Unexpected use of slot 0");
1771
TR_ASSERT(slot0SymRef->getSymbol()->getDataType() == TR::Address, "This is not an address type");
1772
1773
if (loadHiddenSlot == NULL)
1774
loadHiddenSlot = TR::Node::createWithSymRef(TR::aloadi, 1, 1, dltBufChild, shadowSymRef);
1775
1776
// Reinstate slot0
1777
*first32Slots |= 1;
1778
1779
// Defect 121354: this store cannot be eliminated, since stackWalker needs it.
1780
slot0SymRef->getSymbol()->setReinstatedReceiver();
1781
TR::Node *storeSlot0 = TR::Node::createWithSymRef(TR::astore, 1, 1, loadHiddenSlot, slot0SymRef);
1782
newFirstBlock->append(TR::TreeTop::create(comp(), storeSlot0));
1783
}
1784
}
1785
1786
// Defect 131382: we need to make sure parameter GC map right for dead parameters revived by JIT
1787
for (; parmIteratorIdx<parmSlots; parmIteratorIdx++)
1788
{
1789
List<TR::SymbolReference> &slotlist = _methodSymbol->getAutoSymRefs(parmIteratorIdx);
1790
ListIterator<TR::SymbolReference> si(&slotlist);
1791
TR::SymbolReference *parmSymRef = si.getFirst(), *slotSymRef;
1792
TR::ParameterSymbol *parmSym = NULL;
1793
int32_t *currentSlots = slotsDescription + (parmIteratorIdx/32);
1794
TR::Node *addrNode = NULL;
1795
int32_t nodeRealOffset = -1;
1796
1797
for (; parmSymRef; parmSymRef = si.getNext())
1798
{
1799
parmSym = parmSymRef->getSymbol()->getParmSymbol();
1800
if (parmSym)
1801
break;
1802
}
1803
1804
si.reset();
1805
slotSymRef = si.getFirst();
1806
1807
bool OSlotParm = (*currentSlots) & (1<<(parmIteratorIdx%32));
1808
1809
for (; slotSymRef; slotSymRef = si.getNext())
1810
{
1811
if (slotSymRef != parmSymRef)
1812
{
1813
TR::Node *loadNode, *storeNode;
1814
TR::DataType dataType = slotSymRef->getSymbol()->getDataType();
1815
bool zeroIt = ((OSlotParm && dataType!=TR::Address) ||
1816
(!OSlotParm && dataType==TR::Address));
1817
1818
TR_ASSERT(slotSymRef->getSymbol()->getParmSymbol()==NULL, "Multiple parms on the same slot");
1819
if (!zeroIt)
1820
{
1821
int32_t realOffset = (tempSlots+parmSlots-parmIteratorIdx-1) * TR::Compiler->om.sizeofReferenceAddress();
1822
1823
if (isSyncMethod)
1824
realOffset += TR::Compiler->om.sizeofReferenceAddress();
1825
1826
if (TR::Symbol::convertTypeToNumberOfSlots(dataType) == 2)
1827
{
1828
TR_ASSERT(parmIteratorIdx!=tempSlots+parmSlots-1, "Access beyond the temp buffer");
1829
realOffset -= TR::Compiler->om.sizeofReferenceAddress();
1830
}
1831
1832
if (addrNode==NULL || nodeRealOffset!=realOffset)
1833
{
1834
nodeRealOffset = realOffset;
1835
if (comp()->target().is64Bit())
1836
{
1837
TR::Node *constNode = TR::Node::create(TR::lconst, 0);
1838
constNode->setLongInt(realOffset);
1839
addrNode = TR::Node::create(TR::aladd, 2, dltBufChild, constNode);
1840
}
1841
else
1842
addrNode = TR::Node::create(TR::aiadd, 2, dltBufChild, TR::Node::create(TR::iconst, 0, realOffset));
1843
}
1844
loadNode = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectLoad(dataType), 1, 1, addrNode, shadowSymRef);
1845
}
1846
else
1847
{
1848
switch (dataType)
1849
{
1850
case TR::Int32:
1851
loadNode = TR::Node::iconst(0);
1852
break;
1853
1854
case TR::Int64:
1855
loadNode = TR::Node::lconst(0);
1856
break;
1857
1858
case TR::Address:
1859
loadNode = TR::Node::aconst(0);
1860
break;
1861
1862
case TR::Float:
1863
loadNode = TR::Node::create(TR::fconst, 0);
1864
loadNode->setFloat(0.0);
1865
break;
1866
1867
case TR::Double:
1868
loadNode = TR::Node::create(TR::dconst, 0);
1869
loadNode->setDouble(0.0);
1870
break;
1871
1872
default:
1873
TR_ASSERT(false, "Unexpected auto slot data type");
1874
loadNode = TR::Node::iconst(0);
1875
break;
1876
}
1877
}
1878
storeNode = TR::Node::createWithSymRef(comp()->il.opCodeForDirectStore(dataType), 1, 1, loadNode, slotSymRef);
1879
newFirstBlock->append(TR::TreeTop::create(comp(), storeNode));
1880
}
1881
}
1882
1883
if (parmSymRef && parmSym->isReferencedParameter() && parmSym->isCollectedReference() && !OSlotParm)
1884
{
1885
*currentSlots |= 1<<(parmIteratorIdx%32);
1886
parmSym->setReinstatedReceiver();
1887
TR::Node *resetNode = TR::Node::createWithSymRef(TR::astore, 1, 1, TR::Node::aconst(0), parmSymRef);
1888
newFirstBlock->append(TR::TreeTop::create(comp(), resetNode));
1889
}
1890
}
1891
1892
if (tempSlots != 0)
1893
{
1894
int32_t currentBundle, remainInBundle;
1895
1896
slotsDescription += parmSlots/32;
1897
currentBundle = *slotsDescription++;
1898
remainInBundle = 32 - parmSlots%32;
1899
if (remainInBundle != 32)
1900
currentBundle >>= (32 - remainInBundle);
1901
1902
for (int32_t i=0; i < tempSlots; i++)
1903
{
1904
TR::Node *addrNode = NULL;
1905
int32_t nodeRealOffset = -1;
1906
bool isOSlot = currentBundle & 1;
1907
1908
currentBundle >>= 1;
1909
remainInBundle -= 1;
1910
if (remainInBundle==0 && i!=tempSlots-1)
1911
{
1912
currentBundle = *slotsDescription++;
1913
remainInBundle = 32;
1914
}
1915
1916
List<TR::SymbolReference> &list = _methodSymbol->getAutoSymRefs(parmSlots+i);
1917
ListIterator<TR::SymbolReference> iterator(&list);
1918
TR::SymbolReference *symRef = iterator.getFirst();
1919
for (; symRef; symRef = iterator.getNext())
1920
{
1921
TR::Node *loadNode, *storeNode;
1922
TR::DataType dataType = symRef->getSymbol()->getDataType();
1923
bool zeroIt = ((isOSlot && dataType!=TR::Address) ||
1924
(!isOSlot && dataType==TR::Address));
1925
if (!zeroIt)
1926
{
1927
int32_t realOffset = (tempSlots-i-1) * TR::Compiler->om.sizeofReferenceAddress();
1928
1929
if (isSyncMethod)
1930
realOffset += TR::Compiler->om.sizeofReferenceAddress();
1931
1932
if (TR::Symbol::convertTypeToNumberOfSlots(dataType) == 2)
1933
{
1934
TR_ASSERT(i!=tempSlots-1, "Access beyond the temp buffer");
1935
realOffset -= TR::Compiler->om.sizeofReferenceAddress();
1936
}
1937
1938
if (addrNode==NULL || nodeRealOffset!=realOffset)
1939
{
1940
nodeRealOffset = realOffset;
1941
if (comp()->target().is64Bit())
1942
{
1943
TR::Node *constNode = TR::Node::create(TR::lconst, 0);
1944
constNode->setLongInt(realOffset);
1945
addrNode = TR::Node::create(TR::aladd, 2, dltBufChild, constNode);
1946
}
1947
else
1948
addrNode = TR::Node::create(TR::aiadd, 2, dltBufChild, TR::Node::create(TR::iconst, 0, realOffset));
1949
}
1950
loadNode = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectLoad(dataType), 1, 1, addrNode, shadowSymRef);
1951
}
1952
else
1953
{
1954
switch (dataType)
1955
{
1956
case TR::Int32:
1957
loadNode = TR::Node::iconst(0);
1958
break;
1959
1960
case TR::Int64:
1961
loadNode = TR::Node::lconst(0);
1962
break;
1963
1964
case TR::Address:
1965
loadNode = TR::Node::aconst(0);
1966
break;
1967
1968
case TR::Float:
1969
loadNode = TR::Node::create(TR::fconst, 0);
1970
loadNode->setFloat(0.0);
1971
break;
1972
1973
case TR::Double:
1974
loadNode = TR::Node::create(TR::dconst, 0);
1975
loadNode->setDouble(0.0);
1976
break;
1977
1978
default:
1979
TR_ASSERT(false, "Unexpected auto slot data type");
1980
loadNode = TR::Node::iconst(0);
1981
break;
1982
}
1983
}
1984
storeNode = TR::Node::createWithSymRef(comp()->il.opCodeForDirectStore(dataType), 1, 1, loadNode, symRef);
1985
newFirstBlock->append(TR::TreeTop::create(comp(), storeNode));
1986
}
1987
}
1988
}
1989
1990
for (auto nextSymRef = comp()->getMonitorAutoSymRefsInCompiledMethod()->begin(); nextSymRef != comp()->getMonitorAutoSymRefsInCompiledMethod()->end(); ++nextSymRef)
1991
{
1992
TR_ASSERT(!comp()->getOption(TR_MimicInterpreterFrameShape), "cannot initialize sync temp symRefs in DLT block when autos can alias each other\n");
1993
TR::Node *aconstNode = TR::Node::aconst(0);
1994
TR::Node *storeNode = TR::Node::createWithSymRef(TR::astore, 1, 1, aconstNode, *nextSymRef);
1995
storeNode->setLiveMonitorInitStore(true);
1996
newFirstBlock->append(TR::TreeTop::create(comp(), storeNode));
1997
}
1998
1999
newFirstBlock->append(TR::TreeTop::create(comp(), TR::Node::create(TR::Goto, 0, steerTarget)));
2000
if (firstBlock != steerTarget->getNode()->getBlock())
2001
{
2002
cfg()->addEdge(newFirstBlock, steerTarget->getNode()->getBlock());
2003
cfg()->removeEdge(newFirstBlock, firstBlock);
2004
}
2005
}
2006
2007
void
2008
TR_J9ByteCodeIlGenerator::inlineJitCheckIfFinalizeObject(TR::Block *firstBlock)
2009
{
2010
2011
///comp()->dumpMethodTrees("before inlineJitCheckIfFinalizeObject", _methodSymbol);
2012
TR::SymbolReference *finalizeSymRef = comp()->getSymRefTab()->findOrCreateRuntimeHelper(TR_jitCheckIfFinalizeObject, true, true, true);
2013
int32_t origNumBlocks = cfg()->getNextNodeNumber();
2014
2015
for (TR::Block *block = firstBlock; block; block = block->getNextBlock())
2016
{
2017
// ignore processing any new blocks created
2018
//
2019
if (block->getNumber() >= origNumBlocks)
2020
continue;
2021
2022
TR::TreeTop *tt = block->getEntry();
2023
for (; tt != block->getExit(); tt = tt->getNextTreeTop())
2024
{
2025
TR::Node *node = tt->getNode();
2026
if (node->getOpCodeValue() == TR::treetop)
2027
node = node->getFirstChild();
2028
2029
// look for
2030
// vcall jitCheckIfFinalizeObject
2031
// receiverArg
2032
//
2033
// if found, create a diamond control flow
2034
// if (classDepthAndFlags & FINALIZE)
2035
// vcall jitCheckIfFinalizeObject
2036
// else
2037
// remainder
2038
//
2039
bool is64bit = comp()->target().is64Bit();
2040
//
2041
if (node->getOpCode().isCall() &&
2042
(node->getSymbolReference() == finalizeSymRef))
2043
{
2044
TR::Node *vftLoad = TR::Node::createWithSymRef(TR::aloadi, 1, 1,
2045
node->getFirstChild(),
2046
comp()->getSymRefTab()->findOrCreateVftSymbolRef());
2047
2048
TR::ILOpCodes loadOp = is64bit ? TR::lloadi : TR::iloadi;
2049
2050
TR::Node *classDepthAndFlagsNode = TR::Node::createWithSymRef(loadOp, 1, 1,
2051
vftLoad,
2052
comp()->getSymRefTab()->findOrCreateClassAndDepthFlagsSymbolRef());
2053
TR::Node *andConstNode = TR::Node::create(classDepthAndFlagsNode, is64bit ? TR::lconst : TR::iconst, 0);
2054
if (is64bit)
2055
andConstNode->setLongInt(fej9()->getFlagValueForFinalizerCheck());
2056
else
2057
andConstNode->setInt(fej9()->getFlagValueForFinalizerCheck());
2058
2059
TR::Node *andNode = TR::Node::create(is64bit ? TR::land : TR::iand, 2, classDepthAndFlagsNode, andConstNode);
2060
TR::Node *constCheckNode = TR::Node::create(andConstNode, is64bit ? TR::lconst : TR::iconst, 0);
2061
if (is64bit)
2062
constCheckNode->setLongInt(0);
2063
else
2064
constCheckNode->setInt(0);
2065
TR::Node *cmp = TR::Node::createif(is64bit ? TR::iflcmpne : TR::ificmpne,
2066
andNode,
2067
constCheckNode,
2068
NULL);
2069
TR::TreeTop *cmpTree = TR::TreeTop::create(comp(), cmp);
2070
TR::Node *dupCallNode = tt->getNode()->duplicateTree();
2071
TR::TreeTop *dupCallTreeTop = TR::TreeTop::create(comp(), dupCallNode);
2072
block->createConditionalBlocksBeforeTree(tt, cmpTree, dupCallTreeTop, NULL, cfg(), false);
2073
// createConditionalBlocks sets the ifBlock as cold
2074
// reset the flag and setup the appropriate frequency here
2075
//
2076
TR::Block *callBlock = cmp->getBranchDestination()->getNode()->getBlock();
2077
callBlock->setIsCold(false);
2078
callBlock->setFrequency(MAX_COLD_BLOCK_COUNT+1);
2079
///comp()->dumpMethodTrees("after inlineJitCheckIfFinalizeObject", _methodSymbol);
2080
break;
2081
}
2082
}
2083
}
2084
}
2085
2086
//A structure to hold the names of all methods in DecimalFormatHelper that we need to replace with other
2087
//methods.
2088
struct TR_J9ByteCodeIlGenerator::methodRenamePair TR_J9ByteCodeIlGenerator::_decFormatRenames[_numDecFormatRenames] =
2089
{ {"com/ibm/jit/DecimalFormatHelper$FieldPosition.setBeginIndex(I)V", "java/text/FieldPosition.setBeginIndex(I)V"},
2090
{"com/ibm/jit/DecimalFormatHelper$FieldPosition.setEndIndex(I)V", "java/text/FieldPosition.setEndIndex(I)V"},
2091
{"com/ibm/jit/DecimalFormatHelper$FieldPosition.getFieldDelegate()Lcom/ibm/jit/DecimalFormatHelper$FieldDelegate;", "java/text/FieldPosition.getFieldDelegate()Ljava/text/Format$FieldDelegate;"},
2092
{"com/ibm/jit/DecimalFormatHelper$FieldPosition.getFieldAttribute()Ljava/text/Format$Field;", "java/text/FieldPosition.getFieldAttribute()Ljava/text/Format$Field;"},
2093
{"com/ibm/jit/DecimalFormatHelper$DigitList.isZero()Z", "java/text/DigitList.isZero()Z"},
2094
{"com/ibm/jit/DecimalFormatHelper$DigitList.set(ZJ)V", "java/text/DigitList.set(ZJ)V"},
2095
{"com/ibm/jit/DecimalFormatHelper.isGroupingUsed(Ljava/text/NumberFormat;)Z", "java/text/NumberFormat.isGroupingUsed()Z"},
2096
{"com/ibm/jit/DecimalFormatHelper.getBigDecimalMultiplier(Ljava/text/DecimalFormat;)Ljava/math/BigDecimal;", "java/text/DecimalFormat.getBigDecimalMultiplier()Ljava/math/BigDecimal;"},
2097
{"com/ibm/jit/DecimalFormatHelper.subformat(Ljava/text/DecimalFormat;Ljava/lang/StringBuffer;Lcom/ibm/jit/DecimalFormatHelper$FieldDelegate;ZZIIII)Ljava/lang/StringBuffer;", "java/text/DecimalFormat.subformat(Ljava/lang/StringBuffer;Ljava/text/Format$FieldDelegate;ZZIIII)Ljava/lang/StringBuffer;"},
2098
};
2099
2100
//Replaces all methods and fields in DecimalFormatHelper.format routine with appropriate methods and fields.
2101
//returns true if all methods and fields are replaced successfully
2102
bool TR_J9ByteCodeIlGenerator::replaceMembersOfFormat()
2103
{
2104
for (int i =0; i < _numDecFormatRenames; i++)
2105
{
2106
_decFormatRenamesDstSymRef[i] = fej9()->findOrCreateMethodSymRef(comp(), _methodSymbol, _decFormatRenames[i].dstMethodSignature);
2107
}
2108
2109
bool successful = true;
2110
for (TR::TreeTop* tt = _methodSymbol->getFirstTreeTop(); (tt != NULL); tt = tt->getNextRealTreeTop())
2111
{
2112
TR::Node *node = tt->getNode();
2113
if (node->getOpCodeValue() == TR::treetop)
2114
node = node->getFirstChild();
2115
TR::Node *callNode = node;
2116
if (!node->getOpCode().isCall() && (node->getNumChildren() > 0))
2117
callNode = node->getFirstChild();
2118
successful = successful && replaceMethods(tt, callNode);
2119
successful = successful && replaceFieldsAndStatics(tt, callNode);
2120
}
2121
return successful;
2122
}
2123
2124
bool TR_J9ByteCodeIlGenerator::replaceMethods(TR::TreeTop *tt, TR::Node *node)
2125
{
2126
if (!node->getOpCode().isCall() || !node->getOpCode().hasSymbolReference()) return true;
2127
if (node->getSymbolReference()->getSymbol()->castToMethodSymbol()->isHelper()) return true;
2128
TR::Method * method = node->getSymbolReference()->getSymbol()->castToMethodSymbol()->getMethod();
2129
//I use heapAlloc because this function is called many times for a small set of methods.
2130
const char* nodeName = method->signature(trMemory(), heapAlloc);
2131
for (int i = 0; i < _numDecFormatRenames; i++)
2132
{
2133
if (!strcmp(nodeName, _decFormatRenames[i].srcMethodSignature))
2134
{
2135
if (performTransformation(comp(), "%sreplaced %s by %s in [%p]\n",
2136
OPT_DETAILS, _decFormatRenames[i].srcMethodSignature, _decFormatRenames[i].dstMethodSignature, node))
2137
{
2138
if (_decFormatRenamesDstSymRef[i] == NULL)
2139
return false;
2140
node->setSymbolReference(_decFormatRenamesDstSymRef[i]);
2141
return true;
2142
}
2143
else
2144
{
2145
return false;
2146
}
2147
}
2148
}
2149
return true;
2150
}
2151
2152
static bool matchFieldOrStaticName(TR::Compilation* comp, TR::Node* node, char* staticOrFieldName) {
2153
if ((!node->getOpCode().isLoad() && !node->getOpCode().isStore()) ||
2154
!node->getOpCode().hasSymbolReference())
2155
return false;
2156
TR::SymbolReference* symRef = node->getSymbolReference();
2157
TR::Symbol* sym = symRef->getSymbol();
2158
if (sym == NULL || symRef->getCPIndex() < 0) return false;
2159
TR_ResolvedMethod* method = comp->getOwningMethodSymbol(symRef->getOwningMethodIndex())->getResolvedMethod();
2160
if (!method) return false;
2161
switch(sym->getKind()) {
2162
case TR::Symbol::IsStatic:
2163
{
2164
//make sure it's not a "helper" symbol
2165
int32_t index = symRef->getReferenceNumber();
2166
int32_t nonhelperIndex = comp->getSymRefTab()->getNonhelperIndex(comp->getSymRefTab()->getLastCommonNonhelperSymbol());
2167
int32_t numHelperSymbols = comp->getSymRefTab()->getNumHelperSymbols();
2168
if ((index < numHelperSymbols) || (index < nonhelperIndex) || !sym->isStaticField()) return false;
2169
2170
const char * nodeName = method->staticName(symRef->getCPIndex(), comp->trMemory(), stackAlloc);
2171
return !strcmp(nodeName, staticOrFieldName);
2172
}
2173
case TR::Symbol::IsShadow:
2174
{
2175
const char * nodeName = method->fieldName(symRef->getCPIndex(), comp->trMemory(), stackAlloc);
2176
return !strcmp(nodeName, staticOrFieldName);
2177
}
2178
default:
2179
return false;
2180
}
2181
}
2182
2183
bool TR_J9ByteCodeIlGenerator::replaceField(TR::Node* node, char* destClass,
2184
char* destFieldName, char* destFieldSignature,
2185
int parmIndex)
2186
{
2187
TR_OpaqueClassBlock *c = fej9()->getClassFromSignature(destClass, strlen(destClass), comp()->getCurrentMethod());
2188
//When, e.g., AOT is enabled, classes are not loaded at compile time so the
2189
//function above returns NULL
2190
if (c == NULL)
2191
return false;
2192
if (performTransformation(comp(), "%ssymref replaced by %s.%s %s in [%p]\n", OPT_DETAILS, destClass, destFieldName, destFieldSignature, node))
2193
{
2194
//The following code (up to and including the call to initShadowSymbol) has been adapted from
2195
//TR::SymbolReferenceTable::findOrCreateShadowSymbol
2196
uint32_t offset =
2197
fej9()->getInstanceFieldOffset(c, destFieldName, destFieldSignature) +
2198
fej9()->getObjectHeaderSizeInBytes();
2199
2200
TR::DataType type = node->getDataType();
2201
TR::Symbol * sym = TR::Symbol::createShadow(trHeapMemory(), type);
2202
sym->setPrivate();
2203
TR::SymbolReference* symRef =
2204
new (trHeapMemory()) TR::SymbolReference(comp()->getSymRefTab(), sym,
2205
comp()->getMethodSymbol()->getResolvedMethodIndex(),
2206
-1, 0);
2207
comp()->getSymRefTab()->checkUserField(symRef);
2208
//Is the last field (isUnresolvedInCP) set correctly ?
2209
comp()->getSymRefTab()->initShadowSymbol(comp()->getCurrentMethod(), symRef, true, type, offset, false);
2210
2211
//we need to change a field reference f to p.f where p is the first parameter (of class DecimalFormat)
2212
//so we need to make the load/store node an indirect one and add, as a child, an indirect load to load p
2213
if (!node->getOpCode().isIndirect())
2214
{
2215
if (node->getOpCode().isLoad())
2216
{
2217
TR::Node::recreate(node, comp()->il.opCodeForIndirectLoad(type));
2218
node->setNumChildren(1);
2219
}
2220
else
2221
{
2222
TR_ASSERT(node->getOpCode().isStore(), "node can be either a load or a store\n");
2223
TR::Node::recreate(node, comp()->il.opCodeForIndirectStore(type));
2224
node->setNumChildren(2);
2225
node->setChild(1, node->getChild(0));
2226
node->setChild(0, NULL);
2227
}
2228
ListIterator<TR::ParameterSymbol> parms(&_methodSymbol->getParameterList());
2229
TR_ASSERT(parmIndex == 0 || parmIndex == 1, "invalid parmIndex\n");
2230
TR::ParameterSymbol * p = parms.getFirst();
2231
if (parmIndex == 1)
2232
p = parms.getNext();
2233
TR::Node* decFormObjLoad = TR::Node::createLoad(node, symRefTab()->findOrCreateAutoSymbol(_methodSymbol, p->getSlot(), p->getDataType()));
2234
node->setAndIncChild(0, decFormObjLoad);
2235
}
2236
node->setSymbolReference(symRef);
2237
return true;
2238
}
2239
return false;
2240
}
2241
2242
bool TR_J9ByteCodeIlGenerator::replaceStatic(TR::Node* node,
2243
char* dstClassName, char* staticName, char* type)
2244
{
2245
TR_OpaqueClassBlock *c = fej9()->getClassFromSignature(dstClassName, strlen(dstClassName), comp()->getCurrentMethod());
2246
2247
// When, e.g., AOT is enabled, classes are not loaded at compile time so the
2248
// function above returns NULL
2249
//
2250
if (c == NULL)
2251
return false;
2252
2253
void* dataAddress = fej9()->getStaticFieldAddress(c, (unsigned char *) staticName, strlen(staticName),
2254
(unsigned char *) type, strlen(type));
2255
2256
if ( dataAddress != NULL &&
2257
!node->getSymbolReference()->isUnresolved() &&
2258
performTransformation(comp(), "%sreplaced %s.%s in [%p]\n", OPT_DETAILS, dstClassName, staticName, node)
2259
)
2260
{
2261
//I'm not setting the correct SymRef. I'm just changing the address
2262
((TR::StaticSymbol*)node->getSymbolReference()->getSymbol())->setStaticAddress(dataAddress);
2263
return true;
2264
}
2265
else
2266
return false;
2267
}
2268
2269
2270
bool TR_J9ByteCodeIlGenerator::replaceFieldsAndStatics(TR::TreeTop *tt, TR::Node *node) {
2271
bool result = true;
2272
if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.INSTANCE Lcom/ibm/jit/DecimalFormatHelper$FieldPosition;"))
2273
{
2274
//Replace static com/ibm/jit/DecimalFormatHelper.INSTANCE with static java/text/DontCareFieldPosition.INSTANCE
2275
result = replaceStatic(node, "java/text/DontCareFieldPosition", "INSTANCE", "Ljava/text/FieldPosition;");
2276
}
2277
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.doubleDigitsTens [C"))
2278
{
2279
result = replaceStatic(node, "java/math/BigDecimal", "doubleDigitsTens", "[C");
2280
}
2281
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.doubleDigitsOnes [C"))
2282
{
2283
result = replaceStatic(node, "java/math/BigDecimal", "doubleDigitsOnes", "[C");
2284
}
2285
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.multiplier I"))
2286
{
2287
result = replaceField(node, "java/text/DecimalFormat", "multiplier", "I", 0);
2288
}
2289
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.digitList Lcom/ibm/jit/DecimalFormatHelper$DigitList;"))
2290
{
2291
result = replaceField(node, "java/text/DecimalFormat", "digitList", "Ljava/text/DigitList;", 0);
2292
}
2293
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper$DigitList.digits [C"))
2294
{
2295
result = replaceField(node, "java/text/DigitList", "digits", "[C", 0);
2296
}
2297
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper$DigitList.decimalAt I"))
2298
{
2299
result = replaceField(node, "java/text/DigitList", "decimalAt", "I", 0);
2300
}
2301
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper$DigitList.count I"))
2302
{
2303
result = replaceField(node, "java/text/DigitList", "count", "I", 0);
2304
}
2305
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.flags I"))
2306
{
2307
result = replaceField(node, "java/math/BigDecimal", "flags", "I", 1);
2308
}
2309
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.laside J"))
2310
{
2311
result = replaceField(node, "java/math/BigDecimal", "laside", "J", 1);
2312
}
2313
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.scale I"))
2314
{
2315
//Use "scale" for java 6 or 626 and "cachedScale" for java 7
2316
result = replaceField(node, "java/math/BigDecimal", "cachedScale", "I", 1);
2317
}
2318
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.symbols Ljava/text/DecimalFormatSymbols;"))
2319
{
2320
result = replaceField(node, "java/text/DecimalFormat", "symbols", "Ljava/text/DecimalFormatSymbols;", 0);
2321
}
2322
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.isCurrencyFormat Z"))
2323
{
2324
result = replaceField(node, "java/text/DecimalFormat", "isCurrencyFormat", "Z", 0);
2325
}
2326
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.decimalSeparatorAlwaysShown Z"))
2327
{
2328
result = replaceField(node, "java/text/DecimalFormat", "decimalSeparatorAlwaysShown", "Z", 0);
2329
}
2330
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.useExponentialNotation Z"))
2331
{
2332
result = replaceField(node, "java/text/DecimalFormat", "useExponentialNotation", "Z", 0);
2333
}
2334
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.negativePrefix Ljava/lang/String;"))
2335
{
2336
result = replaceField(node, "java/text/DecimalFormat", "negativePrefix", "Ljava/lang/String;", 0);
2337
}
2338
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.negativeSuffix Ljava/lang/String;"))
2339
{
2340
result = replaceField(node, "java/text/DecimalFormat", "negativeSuffix", "Ljava/lang/String;", 0);
2341
}
2342
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.positivePrefix Ljava/lang/String;"))
2343
{
2344
result = replaceField(node, "java/text/DecimalFormat", "positivePrefix", "Ljava/lang/String;", 0);
2345
}
2346
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.positiveSuffix Ljava/lang/String;"))
2347
{
2348
result = replaceField(node, "java/text/DecimalFormat", "positiveSuffix", "Ljava/lang/String;", 0);
2349
}
2350
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.groupingSize B"))
2351
{
2352
result = replaceField(node, "java/text/DecimalFormat", "groupingSize", "B", 0);
2353
}
2354
else if (matchFieldOrStaticName(comp(), node, "com/ibm/jit/DecimalFormatHelper.minExponentDigits B"))
2355
{
2356
result = replaceField(node, "java/text/DecimalFormat", "minExponentDigits", "B", 0);
2357
}
2358
for (int i = 0; i < node->getNumChildren(); i++) {
2359
result = result && replaceFieldsAndStatics(tt, node->getChild(i));
2360
}
2361
return result;
2362
}
2363
2364
/**
2365
* Expand a checkcast tree for an unresolved class.
2366
*
2367
* A ResolveCHK is emitted before the checkcast, and both the ResolveCHK and
2368
* checkcast are skipped when the object tested is null.
2369
*
2370
* Pictorially, transform this:
2371
*
2372
@verbatim
2373
+-<block_$orig>------------------------------+
2374
| ... $pre |
2375
| n1n checkcast |
2376
| n2n $obj |
2377
| n3n loadaddr $klass [unresolved Static] |
2378
| ... $post |
2379
+--------------------------------------------+
2380
@endverbatim
2381
*
2382
* into this:
2383
*
2384
@verbatim
2385
+-<block_$orig>------------------+
2386
| ... $pre |
2387
| ... treetop |
2388
| n2n $obj |
2389
| ... astore $tmp_obj |
2390
| n2n =>$obj |
2391
| ... (more fixupCommoning) |
2392
| ... ifacmpeq --> block_$merge |----------+
2393
| n2n =>$obj | |
2394
| ... aconst NULL | |
2395
+--------------------------------+ |
2396
| |
2397
fallthrough | |
2398
| |
2399
v |
2400
+-<block_$nonnull>---------------------------+ |
2401
| ... ResolveCHK | |
2402
| n3n loadaddr $klass [unresolved Static] | |
2403
| n1n checkcast | |
2404
| ... aload $tmp_obj | |
2405
| n3n =>loadaddr | |
2406
+--------------------------------------------+ |
2407
| |
2408
fallthrough | +-------------------+
2409
| |
2410
v v
2411
+-<block_$merge>--------------+
2412
| $post (w/ fixupCommoning) |
2413
+-----------------------------+
2414
@endverbatim
2415
*
2416
* @param tree The checkcast tree as generated by the walker
2417
*
2418
* @see genCheckCast(int32_t)
2419
* @see expandUnresolvedClassTypeTests(List<TR::TreeTop>*)
2420
*/
2421
void TR_J9ByteCodeIlGenerator::expandUnresolvedClassCheckcast(TR::TreeTop *tree)
2422
{
2423
TR::Node *checkcastNode = tree->getNode();
2424
TR_ASSERT(checkcastNode->getOpCodeValue() == TR::checkcast, "unresolved class checkcast: expected treetop %p node n%un to be checkcast but was %s\n", tree, checkcastNode->getGlobalIndex(), checkcastNode->getOpCode().getName());
2425
2426
TR::Node *objNode = checkcastNode->getFirstChild();
2427
TR::Node *classNode = checkcastNode->getSecondChild();
2428
TR_ASSERT(classNode->getOpCodeValue() == TR::loadaddr, "unresolved class checkcast n%un: expected class child n%un to be loadaddr but was %s\n", checkcastNode->getGlobalIndex(), classNode->getGlobalIndex(), classNode->getOpCode().getName());
2429
TR_ASSERT(classNode->getSymbolReference()->isUnresolved(), "unresolved class checkcast n%un: expected symref of class child n%un to be unresolved\n", checkcastNode->getGlobalIndex(), classNode->getGlobalIndex());
2430
TR_ASSERT(classNode->getReferenceCount() == 1, "unresolved class checkcast n%un: expected class child n%un to have reference count 1\n", checkcastNode->getGlobalIndex(), classNode->getGlobalIndex());
2431
2432
bool trace = comp()->getOption(TR_TraceILGen);
2433
if (trace)
2434
traceMsg(comp(), "expanding unresolved class checkcast n%un in block_%d\n", checkcastNode->getGlobalIndex(), tree->getEnclosingBlock()->getNumber());
2435
2436
TR::Node *objAnchor = TR::Node::create(TR::treetop, 1, objNode);
2437
objAnchor->copyByteCodeInfo(checkcastNode);
2438
tree->insertBefore(TR::TreeTop::create(comp(), objAnchor));
2439
2440
TR::Block *headBlock = tree->getEnclosingBlock();
2441
const bool fixupCommoning = true;
2442
TR::Block *nonNullCaseBlock = headBlock->split(tree, cfg(), fixupCommoning);
2443
TR::Block *tailBlock = nonNullCaseBlock->split(tree->getNextTreeTop(), cfg(), fixupCommoning);
2444
2445
headBlock->getExit()->getNode()->copyByteCodeInfo(checkcastNode);
2446
nonNullCaseBlock->getEntry()->getNode()->copyByteCodeInfo(checkcastNode);
2447
nonNullCaseBlock->getExit()->getNode()->copyByteCodeInfo(checkcastNode);
2448
tailBlock->getEntry()->getNode()->copyByteCodeInfo(checkcastNode);
2449
2450
TR::Node *aconstNull = TR::Node::aconst(0);
2451
TR::Node *nullTest = TR::Node::createif(TR::ifacmpeq, objNode, aconstNull, tailBlock->getEntry());
2452
aconstNull->copyByteCodeInfo(checkcastNode);
2453
nullTest->copyByteCodeInfo(checkcastNode);
2454
headBlock->append(TR::TreeTop::create(comp(), nullTest));
2455
cfg()->addEdge(headBlock, tailBlock);
2456
2457
TR_ASSERT(checkcastNode->getSecondChild() == classNode, "unresolved class checkcast n%un: split block should not have replaced class child n%un with n%un\n", checkcastNode->getGlobalIndex(), classNode->getGlobalIndex(), checkcastNode->getSecondChild()->getGlobalIndex());
2458
TR::Node *resolveCheckNode = genResolveCheck(classNode);
2459
resolveCheckNode->copyByteCodeInfo(checkcastNode);
2460
nonNullCaseBlock->prepend(TR::TreeTop::create(comp(), resolveCheckNode));
2461
2462
if (trace)
2463
traceMsg(comp(), "\tblock_%d: resolve, checkcast\n\tblock_%d: tail of original block\n", nonNullCaseBlock->getNumber(), tailBlock->getNumber());
2464
}
2465
2466
/**
2467
* Expand an instanceof tree for an unresolved class.
2468
*
2469
* A ResolveCHK is emitted before the instanceof, and both the ResolveCHK and
2470
* instanceof are skipped when the object tested is null. In that case, the
2471
* result is false. In the remainder of the block, occurrences of the original
2472
* instanceof node are made into occurrences of an iload of a new temp, into
2473
* which each of the conditional blocks stores the appropriate result.
2474
*
2475
* Pictorially, transform this:
2476
*
2477
@verbatim
2478
+-<block_$orig>---------------------------------+
2479
| ... $pre |
2480
| n1n treetop |
2481
| n2n instanceof |
2482
| n3n $obj |
2483
| n4n loadaddr $klass [unresolved Static] |
2484
| ... $post |
2485
+-----------------------------------------------+
2486
@endverbatim
2487
*
2488
* into this:
2489
*
2490
@verbatim
2491
+-<block_$orig>------------------+
2492
| ... $pre |
2493
| ... treetop |
2494
| n3n $obj |
2495
| ... astore $tmp_obj |
2496
| n3n =>$obj |
2497
| ... (more fixupCommoning) |
2498
| ... ifacmpeq --> block_$null |-----------------+
2499
| n3n =>$obj | |
2500
| ... aconst NULL | |
2501
+--------------------------------+ |
2502
| |
2503
fallthrough | |
2504
| |
2505
v |
2506
+-<block_$nonnull>-----------------------+ v
2507
| ResolveCHK | +-<block_$null>----------+
2508
| loadaddr $klass [unresolved Static] | | istore $tmp_result |
2509
| istore $tmp_result | | iconst 0 |
2510
| instanceof | | goto --> block_$merge |
2511
| aload $tmp_obj | +------------------------+
2512
| =>loadaddr | |
2513
+----------------------------------------+ |
2514
| |
2515
fallthrough | +--------------------------+
2516
| |
2517
v v
2518
+-<block_$merge>-----------------+
2519
| n1n treetop |
2520
| n2n iload $tmp_result |
2521
| ... $post (w/ fixupCommoning) |
2522
+--------------------------------+
2523
@endverbatim
2524
*
2525
* except that the treetop n1n is removed from the merge block, because it's
2526
* clearly unnecessary.
2527
*
2528
* @param tree The instanceof tree as generated by the walker
2529
*
2530
* @see genInstanceof(int32_t)
2531
* @see expandUnresolvedClassTypeTests(List<TR::TreeTop>*)
2532
*/
2533
void TR_J9ByteCodeIlGenerator::expandUnresolvedClassInstanceof(TR::TreeTop *tree)
2534
{
2535
TR::Node *treetopNode = tree->getNode();
2536
TR_ASSERT(treetopNode->getOpCodeValue() == TR::treetop, "unresolved class instanceof: expected treetop %p node n%un to be treetop but was %s\n", tree, treetopNode->getGlobalIndex(), treetopNode->getOpCode().getName());
2537
2538
TR::Node *instanceofNode = treetopNode->getFirstChild();
2539
TR_ASSERT(instanceofNode->getOpCodeValue() == TR::instanceof, "unresolved class instanceof: expected treetop %p node n%un child n%un to be instanceof but was %s\n", tree, treetopNode->getGlobalIndex(), instanceofNode->getGlobalIndex(), instanceofNode->getOpCode().getName());
2540
2541
TR::Node *objNode = instanceofNode->getFirstChild();
2542
TR::Node *origClassNode = instanceofNode->getSecondChild();
2543
TR_ASSERT(origClassNode->getOpCodeValue() == TR::loadaddr, "unresolved class instanceof n%un: expected class child n%un to be loadaddr but was %s\n", instanceofNode->getGlobalIndex(), origClassNode->getGlobalIndex(), origClassNode->getOpCode().getName());
2544
TR_ASSERT(origClassNode->getSymbolReference()->isUnresolved(), "unresolved class instanceof n%un: expected symref of class child n%un to be unresolved\n", instanceofNode->getGlobalIndex(), origClassNode->getGlobalIndex());
2545
2546
bool trace = comp()->getOption(TR_TraceILGen);
2547
if (trace)
2548
traceMsg(comp(), "expanding unresolved class instanceof n%un in block_%d\n", instanceofNode->getGlobalIndex(), tree->getEnclosingBlock()->getNumber());
2549
2550
TR::Node *objAnchor = TR::Node::create(TR::treetop, 1, objNode);
2551
objAnchor->copyByteCodeInfo(instanceofNode);
2552
tree->insertBefore(TR::TreeTop::create(comp(), objAnchor));
2553
2554
// create blocks
2555
TR::Block *headBlock = tree->getEnclosingBlock();
2556
const bool fixupCommoning = true;
2557
TR::Block *nonNullCaseBlock = headBlock->split(tree, cfg(), fixupCommoning);
2558
TR::Block *tailBlock = nonNullCaseBlock->split(tree, cfg(), fixupCommoning);
2559
TR::Block *nullCaseBlock = TR::Block::createEmptyBlock(comp());
2560
cfg()->addNode(nullCaseBlock);
2561
cfg()->findLastTreeTop()->join(nullCaseBlock->getEntry());
2562
2563
headBlock->getExit()->getNode()->copyByteCodeInfo(instanceofNode);
2564
nonNullCaseBlock->getEntry()->getNode()->copyByteCodeInfo(instanceofNode);
2565
nonNullCaseBlock->getExit()->getNode()->copyByteCodeInfo(instanceofNode);
2566
nullCaseBlock->getEntry()->getNode()->copyByteCodeInfo(instanceofNode);
2567
nullCaseBlock->getExit()->getNode()->copyByteCodeInfo(instanceofNode);
2568
tailBlock->getEntry()->getNode()->copyByteCodeInfo(instanceofNode);
2569
2570
// headBlock ends with a null test conditionally jumping to nullCaseBlock
2571
TR::Node *aconstNull = TR::Node::aconst(0);
2572
TR::Node *nullTest = TR::Node::createif(TR::ifacmpeq, objNode, aconstNull, nullCaseBlock->getEntry());
2573
aconstNull->copyByteCodeInfo(instanceofNode);
2574
nullTest->copyByteCodeInfo(instanceofNode);
2575
headBlock->append(TR::TreeTop::create(comp(), nullTest));
2576
cfg()->addEdge(headBlock, nullCaseBlock);
2577
2578
// New temporary for the result of instanceof.
2579
TR::SymbolReference *resultTemp = symRefTab()->createTemporary(_methodSymbol, TR::Int32);
2580
2581
// In the null case, instanceof returns false (without resolving the class)
2582
TR::Node *iconst0 = TR::Node::iconst(0);
2583
TR::Node *store0 = TR::Node::createWithSymRef(TR::istore, 1, 1, iconst0, resultTemp);
2584
iconst0->copyByteCodeInfo(instanceofNode);
2585
store0->copyByteCodeInfo(instanceofNode);
2586
nullCaseBlock->append(TR::TreeTop::create(comp(), store0));
2587
TR::Node *gotoTail = TR::Node::create(TR::Goto, 0, tailBlock->getEntry());
2588
gotoTail->copyByteCodeInfo(instanceofNode);
2589
nullCaseBlock->append(TR::TreeTop::create(comp(), gotoTail));
2590
cfg()->addEdge(nullCaseBlock, tailBlock);
2591
2592
// In the non-null case, compute instanceof after resolving the class
2593
TR::TreeTop *newInstanceofTree = tree->duplicateTree();
2594
TR::Node *resultStoreNode = newInstanceofTree->getNode();
2595
resultStoreNode = TR::Node::recreateWithSymRef(resultStoreNode, TR::istore, resultTemp);
2596
TR::Node *classNode = resultStoreNode->getFirstChild()->getSecondChild();
2597
TR::Node *resolveCheckNode = genResolveCheck(classNode);
2598
resolveCheckNode->copyByteCodeInfo(instanceofNode);
2599
nonNullCaseBlock->append(TR::TreeTop::create(comp(), resolveCheckNode));
2600
nonNullCaseBlock->append(newInstanceofTree);
2601
2602
// Uses of the original instanceof will now load the temp instead
2603
instanceofNode = TR::Node::recreateWithSymRef(instanceofNode, TR::iload, resultTemp);
2604
instanceofNode->removeAllChildren();
2605
2606
// Remove the tree that was originally anchoring instanceof
2607
const bool decRefOriginalTreetopNode = true;
2608
tree->unlink(decRefOriginalTreetopNode);
2609
2610
if (trace)
2611
{
2612
traceMsg(comp(), "\tresult in temp #%d\n", resultTemp->getReferenceNumber());
2613
traceMsg(comp(), "\tblock_%d: resolve, instanceof\n", nonNullCaseBlock->getNumber());
2614
traceMsg(comp(), "\tblock_%d: false\n", nullCaseBlock->getNumber());
2615
traceMsg(comp(), "\tblock_%d: tail of original block\n", tailBlock->getNumber());
2616
}
2617
}
2618
2619
bool TR_J9ByteCodeIlGenerator::skipInvokeSpecialInterfaceTypeChecks()
2620
{
2621
static const bool disable =
2622
feGetEnv("TR_skipInvokeSpecialInterfaceTypeChecks") != NULL;
2623
return disable;
2624
}
2625
2626
/**
2627
* Expand a call tree for invokespecial within an interface.
2628
*
2629
* An explicit type test is inserted ahead of the call to ensure that the
2630
* receiver is an instance of the containing interface. The type test is in
2631
* terms of instanceof, so it will fail when the receiver is null. The call's
2632
* null check (if any) is moved before the type test so that it gets the first
2633
* opportunity to throw.
2634
*
2635
* Pictorially, transform this:
2636
*
2637
@verbatim
2638
+-<block_$orig>-------------+
2639
| ... $pre |
2640
| ... NULLCHK |
2641
| n1n call X.foo(...)T |
2642
| n2n $receiver |
2643
| ...args |
2644
| ... $post |
2645
+---------------------------+
2646
@endverbatim
2647
*
2648
* into the following, where @c $Interface is the interface type that was
2649
* detected for @c _invokeSpecialInterface:
2650
*
2651
@verbatim
2652
+-<block_$orig>------------------+
2653
| ... $pre |
2654
| ... NULLCHK |
2655
| ... PassThrough |
2656
| n2n $receiver |
2657
| ... astore $tmp_receiver |
2658
| n2n ==>$receiver |
2659
| ... (more fixupCommoning) |
2660
| ... ificmpne --> block_$ok |-----+
2661
| instanceof | |
2662
| ==>$receiver | |
2663
| loadaddr $Interface | |
2664
| iconst 0 | |
2665
+--------------------------------+ |
2666
| |
2667
fallthrough | |
2668
| |
2669
v |
2670
+-<block_$fail>-(cold)-------------+ |
2671
| ... (throw IllegalAccessError) | |
2672
+----------------------------------+ |
2673
|
2674
+-----------------------+
2675
|
2676
v
2677
+-<block_$ok>--------------------+
2678
| ... treetop |
2679
| n1n call X.foo(...)T |
2680
| ... aload $tmp_receiver |
2681
| ...args |
2682
| ... $post (w/ fixupCommoning) |
2683
+--------------------------------+
2684
@endverbatim
2685
*
2686
* @param tree The call tree as generated by the walker
2687
*/
2688
2689
void TR_J9ByteCodeIlGenerator::expandInvokeSpecialInterface(TR::TreeTop *tree)
2690
{
2691
TR_ASSERT(
2692
!comp()->compileRelocatableCode(),
2693
"in expandInvokeSpecialInterface under AOT\n");
2694
2695
TR_ASSERT(
2696
!skipInvokeSpecialInterfaceTypeChecks(),
2697
"in expandInvokeSpecialInterface, but it is disabled\n");
2698
2699
const bool trace = comp()->getOption(TR_TraceILGen);
2700
static const bool verbose =
2701
feGetEnv("TR_verboseInvokeSpecialInterface") != NULL;
2702
2703
if (trace)
2704
{
2705
traceMsg(comp(),
2706
"expanding invokespecial in interface method at n%un\n",
2707
tree->getNode()->getGlobalIndex());
2708
if (verbose)
2709
comp()->dumpMethodTrees("Trees before expanding invokespecial", _methodSymbol);
2710
}
2711
2712
TR::Node * const parent = tree->getNode();
2713
TR::Node * const callNode = parent->getChild(0);
2714
TR::Node * const receiver = callNode->getArgument(0);
2715
2716
// Temporarily set _bcIndex so that new nodes will pick it up
2717
const int32_t rememberedBcIndex = _bcIndex;
2718
_bcIndex = callNode->getByteCodeIndex();
2719
2720
// Separate the null check if there is one, so it will precede the type test.
2721
TR::TransformUtil::separateNullCheck(comp(), tree, trace);
2722
2723
// Insert the type test
2724
TR::SymbolReference * const ifaceSR =
2725
symRefTab()->findOrCreateClassSymbol(_methodSymbol, -1, _invokeSpecialInterface);
2726
TR::Node * const iface = TR::Node::createWithSymRef(TR::loadaddr, 0, ifaceSR);
2727
2728
TR::SymbolReference * const instofSR =
2729
symRefTab()->findOrCreateInstanceOfSymbolRef(_methodSymbol);
2730
TR::Node * const instof =
2731
TR::Node::createWithSymRef(TR::instanceof, 2, 2, receiver, iface, instofSR);
2732
2733
TR::Node * const typeTest = TR::Node::createif(
2734
TR::ificmpne,
2735
instof,
2736
TR::Node::iconst(0));
2737
2738
tree->insertBefore(TR::TreeTop::create(comp(), typeTest));
2739
2740
if (trace)
2741
traceMsg(comp(), "Inserted type test n%un\n", typeTest->getGlobalIndex());
2742
2743
// Split block between type test and call
2744
TR::Block * const headBlock = tree->getEnclosingBlock();
2745
2746
const bool fixupCommoning = true;
2747
TR::Block * const failBlock = headBlock->split(tree, cfg(), fixupCommoning);
2748
TR::Block * const okBlock = failBlock->split(tree, cfg(), fixupCommoning);
2749
2750
if (trace)
2751
{
2752
traceMsg(comp(),
2753
"Split block_%d into:\n"
2754
"\tblock_%d (preceding code, and type test),\n"
2755
"\tblock_%d (helper call for type test failure)\n"
2756
"\tblock_%d (successful call, and succeeding code)\n",
2757
headBlock->getNumber(),
2758
headBlock->getNumber(),
2759
failBlock->getNumber(),
2760
okBlock->getNumber());
2761
}
2762
2763
// Fix branch destination
2764
typeTest->setBranchDestination(okBlock->getEntry());
2765
cfg()->addEdge(headBlock, okBlock);
2766
2767
// Failure case: throw IllegalAccessError by calling jitThrowIncompatibleReceiver
2768
failBlock->setIsCold();
2769
failBlock->setFrequency(UNKNOWN_COLD_BLOCK_COUNT);
2770
2771
TR::Node * const rejectedVFT = TR::Node::createWithSymRef(
2772
TR::aloadi,
2773
1,
2774
1,
2775
callNode->getArgument(0)->duplicateTree(), // load split temp
2776
symRefTab()->findOrCreateVftSymbolRef());
2777
2778
TR::Node * const helperCall = TR::Node::createWithSymRef(
2779
TR::call,
2780
2,
2781
2,
2782
iface->duplicateTree(), // avoid commoning across blocks
2783
rejectedVFT,
2784
symRefTab()->findOrCreateIncompatibleReceiverSymbolRef(_methodSymbol));
2785
2786
failBlock->append(TR::TreeTop::create(comp(),
2787
TR::Node::create(TR::treetop, 1, helperCall)));
2788
2789
bool voidReturn = _methodSymbol->getResolvedMethod()->returnOpCode() == TR::Return;
2790
TR::Node *retNode = TR::Node::create(_methodSymbol->getResolvedMethod()->returnOpCode(), voidReturn?0:1);
2791
if (!voidReturn)
2792
{
2793
TR::Node *retValNode = TR::Node::create(comp()->il.opCodeForConst(_methodSymbol->getResolvedMethod()->returnType()), 0);
2794
retValNode->setLongInt(0);
2795
retNode->setAndIncChild(0, retValNode);
2796
}
2797
failBlock->append(TR::TreeTop::create(comp(), retNode));
2798
2799
if (trace)
2800
{
2801
traceMsg(comp(),
2802
"generated helper call n%un for type test failure\n",
2803
helperCall->getGlobalIndex());
2804
}
2805
2806
cfg()->removeEdge(failBlock, okBlock);
2807
cfg()->addEdge(failBlock, cfg()->getEnd());
2808
2809
if (trace && verbose)
2810
comp()->dumpMethodTrees("Trees after expanding invokespecial", _methodSymbol);
2811
2812
_bcIndex = rememberedBcIndex;
2813
}
2814
2815
TR::Node*
2816
TR_J9ByteCodeIlGenerator::loadFromMethodTypeTable(TR::Node* methodHandleInvokeCall)
2817
{
2818
int32_t cpIndex = next2Bytes();
2819
TR::SymbolReference *symRef = symRefTab()->findOrCreateMethodTypeTableEntrySymbol(_methodSymbol, cpIndex);
2820
TR::Node *methodType = TR::Node::createWithSymRef(methodHandleInvokeCall, TR::aload, 0, symRef);
2821
if (!symRef->isUnresolved())
2822
{
2823
if (_methodSymbol->getResolvedMethod()->methodTypeTableEntryAddress(cpIndex))
2824
methodType->setIsNonNull(true);
2825
else
2826
methodType->setIsNull(true);
2827
}
2828
2829
return methodType;
2830
}
2831
2832
2833
TR::Node*
2834
TR_J9ByteCodeIlGenerator::loadCallSiteMethodTypeFromCP(TR::Node* methodHandleInvokeCall)
2835
{
2836
int32_t cpIndex = next2Bytes();
2837
TR_ASSERT(method()->isMethodTypeConstant(cpIndex), "Address-type CP entry %d must be methodType", cpIndex);
2838
TR::SymbolReference *symRef = symRefTab()->findOrCreateMethodTypeSymbol(_methodSymbol, cpIndex);
2839
TR::Node* methodType = TR::Node::createWithSymRef(methodHandleInvokeCall, TR::aload, 0, symRef);
2840
return methodType;
2841
}
2842
2843
TR::Node*
2844
TR_J9ByteCodeIlGenerator::loadCallSiteMethodType(TR::Node* methodHandleInvokeCall)
2845
{
2846
if (fej9()->hasMethodTypesSideTable())
2847
return loadFromMethodTypeTable(methodHandleInvokeCall);
2848
else
2849
return loadCallSiteMethodTypeFromCP(methodHandleInvokeCall);
2850
}
2851
2852
void TR_J9ByteCodeIlGenerator::insertCustomizationLogicTreeIfEnabled(TR::TreeTop* tree, TR::Node* methodHandle)
2853
{
2854
if (comp()->getOption(TR_EnableMHCustomizationLogicCalls))
2855
{
2856
TR::SymbolReference *doCustomizationLogic = comp()->getSymRefTab()->methodSymRefFromName(_methodSymbol, JSR292_MethodHandle, "doCustomizationLogic", "()V", TR::MethodSymbol::Special);
2857
TR::Node* customization = TR::Node::createWithSymRef(TR::call, 1, 1, methodHandle, doCustomizationLogic);
2858
customization->getByteCodeInfo().setDoNotProfile(true);
2859
tree->insertBefore(TR::TreeTop::create(comp(), TR::Node::create(TR::treetop, 1, customization)));
2860
2861
if (comp()->getOption(TR_TraceILGen))
2862
{
2863
traceMsg(comp(), "Inserted call to doCustomizationLogic n%dn %p\n", customization->getGlobalIndex(), customization);
2864
}
2865
}
2866
}
2867
2868
/** \brief
2869
* Expand a MethodHandle.invokeExact call generated from invokeHandle
2870
*
2871
* Transforms the following tree
2872
*
2873
@verbatim
2874
... NULLCHK
2875
n1n xcalli MethodHandle.invokeExact
2876
n2n lconst 0
2877
n3n $receiver
2878
...args
2879
@endverbatim
2880
*
2881
* into
2882
*
2883
@verbatim
2884
... NULLCHK
2885
... PassThrough
2886
n3n $receiver
2887
... acall MethodHandle.getType
2888
==>$receiver
2889
... ZEROCHK
2890
acmpeq
2891
$callSiteMethodType
2892
==>acall MethodHandle.getType
2893
... lcall MethodHandle.invokeExactTargetAddress
2894
==>$receiver
2895
n1n xcalli MethodHandle.invokeExact
2896
==>lcall MethodHandle.invokeExactTargetAddress
2897
==>$receiver
2898
...args
2899
@endverbatim
2900
*
2901
* \param tree
2902
* Tree of the invokeHandle call.
2903
*
2904
* \note
2905
* A call to doCustomizationLogic will be inserted if customization
2906
* logic is enabled for invocations outside of thunk archetype.
2907
*/
2908
void TR_J9ByteCodeIlGenerator::expandInvokeHandle(TR::TreeTop *tree)
2909
{
2910
TR_ASSERT(!comp()->compileRelocatableCode(), "in expandInvokeHandle under AOT\n");
2911
2912
if (comp()->getOption(TR_TraceILGen))
2913
{
2914
traceMsg(comp(), "expanding invokehandle at n%dn\n", tree->getNode()->getGlobalIndex());
2915
}
2916
2917
TR::Node * callNode = tree->getNode()->getChild(0);
2918
TR::Node * receiverHandle = callNode->getArgument(0);
2919
callNode->getByteCodeInfo().setDoNotProfile(true);
2920
2921
TR::Node* callSiteMethodType = loadCallSiteMethodType(callNode);
2922
2923
if (callSiteMethodType->getSymbolReference()->isUnresolved())
2924
{
2925
TR::Node *resolveChkOnMethodType = TR::Node::createWithSymRef(callNode, TR::ResolveCHK, 1, callSiteMethodType, comp()->getSymRefTab()->findOrCreateResolveCheckSymbolRef(_methodSymbol));
2926
tree->insertBefore(TR::TreeTop::create(comp(), resolveChkOnMethodType));
2927
}
2928
2929
// Generate zerochk
2930
TR::Node* zerochkNode = genHandleTypeCheck(receiverHandle, callSiteMethodType);
2931
tree->insertBefore(TR::TreeTop::create(comp(), zerochkNode));
2932
2933
if (comp()->getOption(TR_TraceILGen))
2934
{
2935
traceMsg(comp(), "Inserted ZEROCHK n%dn %p\n", zerochkNode->getGlobalIndex(), zerochkNode);
2936
}
2937
2938
insertCustomizationLogicTreeIfEnabled(tree, receiverHandle);
2939
2940
expandInvokeExact(tree);
2941
}
2942
2943
/** \brief
2944
* Expand a MethodHandle.invokeExact call generated from invokeDynamic.
2945
*
2946
* Transforms the following tree
2947
*
2948
@verbatim
2949
... NULLCHK
2950
n1n xcalli MethodHandle.invokeExact
2951
n2n lconst 0
2952
n3n $receiver
2953
...args
2954
@endverbatim
2955
*
2956
* into
2957
*
2958
@verbatim
2959
... NULLCHK
2960
... PassThrough
2961
n3n $receiver
2962
... lcall MethodHandle.invokeExactTargetAddress
2963
==>$receiver
2964
n1n xcalli MethodHandle.invokeExact
2965
==>lcall MethodHandle.invokeExactTargetAddress
2966
==>$receiver
2967
...args
2968
@endverbatim
2969
*
2970
* \param tree
2971
* Tree of the invokeExact call.
2972
*
2973
* \note
2974
* A call to doCustomizationLogic will be inserted if customization
2975
* logic is enabled for invocations outside of thunk archetype.
2976
*/
2977
void TR_J9ByteCodeIlGenerator::expandInvokeDynamic(TR::TreeTop *tree)
2978
{
2979
TR_ASSERT(!comp()->compileRelocatableCode(), "in expandInvokeDynamic under AOT\n");
2980
2981
if (comp()->getOption(TR_TraceILGen))
2982
{
2983
traceMsg(comp(), "expanding invokeDynamic at n%dn\n", tree->getNode()->getGlobalIndex());
2984
}
2985
2986
TR::Node * callNode = tree->getNode()->getChild(0);
2987
TR::Node * receiverHandle = callNode->getArgument(0);
2988
callNode->getByteCodeInfo().setDoNotProfile(true);
2989
2990
insertCustomizationLogicTreeIfEnabled(tree, receiverHandle);
2991
expandInvokeExact(tree);
2992
}
2993
2994
/** \brief
2995
* Expand a MethodHandle.invokeExact call generated from invokeHandleGeneric.
2996
*
2997
* Transforms the following tree
2998
*
2999
@verbatim
3000
... NULLCHK
3001
n1n xcalli MethodHandle.invokeExact
3002
n2n lconst 0
3003
n3n $receiver
3004
...args
3005
@endverbatim
3006
*
3007
* into
3008
*
3009
@verbatim
3010
... NULLCHK
3011
... PassThrough
3012
n3n $receiver
3013
... acall MethodHandle.asType
3014
==>$receiver
3015
... $callSiteMethodType
3016
... lcall MethodHandle.invokeExactTargetAddress
3017
==>acall MethodHandle.asType
3018
n1n xcalli MethodHandle.invokeExact
3019
==>lcall MethodHandle.invokeExactTargetAddress
3020
==>acall MethodHandle.asType
3021
...args
3022
@endverbatim
3023
*
3024
* \param tree
3025
* Tree of the invokeExact call.
3026
*
3027
* \note
3028
* A call to doCustomizationLogic will be inserted if customization
3029
* logic is enabled for invocations outside of thunk archetype.
3030
*
3031
*/
3032
void TR_J9ByteCodeIlGenerator::expandInvokeHandleGeneric(TR::TreeTop *tree)
3033
{
3034
TR_ASSERT(!comp()->compileRelocatableCode(), "in expandInvokeHandleGeneric under AOT\n");
3035
3036
if (comp()->getOption(TR_TraceILGen))
3037
{
3038
traceMsg(comp(), "expanding invokeHandleGeneric at n%dn\n", tree->getNode()->getGlobalIndex());
3039
}
3040
3041
TR::Node * callNode = tree->getNode()->getChild(0);
3042
TR::Node * receiverHandle = callNode->getArgument(0);
3043
callNode->getByteCodeInfo().setDoNotProfile(true);
3044
3045
TR::Node* callSiteMethodType = loadCallSiteMethodType(callNode);
3046
if (callSiteMethodType->getSymbolReference()->isUnresolved())
3047
{
3048
TR::Node *resolveChkOnMethodType = TR::Node::createWithSymRef(callNode, TR::ResolveCHK, 1, callSiteMethodType, comp()->getSymRefTab()->findOrCreateResolveCheckSymbolRef(_methodSymbol));
3049
tree->insertBefore(TR::TreeTop::create(comp(), resolveChkOnMethodType));
3050
}
3051
3052
TR::SymbolReference *typeConversionSymRef = comp()->getSymRefTab()->methodSymRefFromName(_methodSymbol, JSR292_MethodHandle, JSR292_asType, JSR292_asTypeSig, TR::MethodSymbol::Static);
3053
TR::Node* asType = TR::Node::createWithSymRef(callNode, TR::acall, 2, typeConversionSymRef);
3054
asType->setAndIncChild(0, receiverHandle);
3055
asType->setAndIncChild(1, callSiteMethodType);
3056
asType->getByteCodeInfo().setDoNotProfile(true);
3057
tree->insertBefore(TR::TreeTop::create(comp(), TR::Node::create(callNode, TR::treetop, 1, asType)));
3058
3059
if (comp()->getOption(TR_TraceILGen))
3060
{
3061
traceMsg(comp(), "Inserted asType call n%dn %p\n", asType->getGlobalIndex(), asType);
3062
}
3063
3064
int32_t receiverChildIndex = callNode->getFirstArgumentIndex();
3065
callNode->setAndIncChild(receiverChildIndex, asType);
3066
receiverHandle->recursivelyDecReferenceCount();
3067
3068
insertCustomizationLogicTreeIfEnabled(tree, asType);
3069
3070
expandInvokeExact(tree);
3071
}
3072
3073
/** \brief
3074
* Expand a MethodHandle.invokeExact call.
3075
*
3076
* Transforms the following tree
3077
*
3078
@verbatim
3079
... NULLCHK
3080
n1n xcalli MethodHandle.invokeExact
3081
n2n lconst 0
3082
n3n $receiver
3083
...args
3084
@endverbatim
3085
*
3086
* into
3087
*
3088
@verbatim
3089
... NULLCHK
3090
... PassThrough
3091
n3n $receiver
3092
... lcall MethodHandle.invokeExactTargetAddress
3093
==>$receiver
3094
n1n xcalli MethodHandle.invokeExact
3095
==>lcall MethodHandle.invokeExactTargetAddress
3096
==>$receiver
3097
...args
3098
@endverbatim
3099
*
3100
* \param tree
3101
* Tree of the invokeExact call.
3102
*/
3103
void TR_J9ByteCodeIlGenerator::expandInvokeExact(TR::TreeTop *tree)
3104
{
3105
TR_ASSERT(!comp()->compileRelocatableCode(), "in expandInvokeExact under AOT\n");
3106
3107
if (comp()->getOption(TR_TraceILGen))
3108
{
3109
traceMsg(comp(), "expanding invokeExact at n%dn\n", tree->getNode()->getGlobalIndex());
3110
}
3111
3112
TR::Node * callNode = tree->getNode()->getChild(0);
3113
TR::Node * receiverHandle = callNode->getArgument(0);
3114
callNode->getByteCodeInfo().setDoNotProfile(true);
3115
3116
// Get the method address
3117
uint32_t offset = fej9()->getInstanceFieldOffsetIncludingHeader("Ljava/lang/invoke/MethodHandle;", "thunks", "Ljava/lang/invoke/ThunkTuple;", method());
3118
TR::SymbolReference *thunksSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(_methodSymbol,
3119
TR::Symbol::Java_lang_invoke_MethodHandle_thunks,
3120
TR::Address,
3121
offset,
3122
false,
3123
false,
3124
false,
3125
"java/lang/invoke/MethodHandle.thunks Ljava/lang/invoke/ThunkTuple;");
3126
TR::Node *thunksNode = TR::Node::createWithSymRef(callNode, comp()->il.opCodeForIndirectLoad(TR::Address), 1, receiverHandle, thunksSymRef);
3127
thunksNode->setIsNonNull(true);
3128
3129
3130
offset = fej9()->getInstanceFieldOffsetIncludingHeader("Ljava/lang/invoke/ThunkTuple;", "invokeExactThunk", "J", method());
3131
TR::SymbolReference *invokeExactTargetAddrSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(_methodSymbol,
3132
TR::Symbol::Java_lang_invoke_ThunkTuple_invokeExactThunk,
3133
TR::Int64,
3134
offset,
3135
false,
3136
false,
3137
true,
3138
"java/lang/invoke/ThunkTuple.invokeExactThunk J");
3139
TR::Node *invokeExactTargetAddr = TR::Node::createWithSymRef(callNode, comp()->il.opCodeForIndirectLoad(TR::Int64), 1, thunksNode, invokeExactTargetAddrSymRef);
3140
tree->insertBefore(TR::TreeTop::create(comp(), TR::Node::create(callNode, TR::treetop, 1, invokeExactTargetAddr)));
3141
3142
if (comp()->getOption(TR_TraceILGen))
3143
{
3144
traceMsg(comp(), "Replacing first child n%dn with invoke exact thunk address n%dn\n", callNode->getFirstChild()->getGlobalIndex(), invokeExactTargetAddr->getGlobalIndex());
3145
}
3146
3147
// Replace the `lconst 0` node with the actual thunk address
3148
TR::Node *lnode = callNode->getFirstChild();
3149
callNode->setAndIncChild(0, invokeExactTargetAddr);
3150
lnode->decReferenceCount();
3151
}
3152
3153
/** \brief
3154
* Expand MethodHandle.invokeExact calls generated from different bytecodes.
3155
*
3156
* \param tree
3157
* Tree of the invokeExact call.
3158
*/
3159
void TR_J9ByteCodeIlGenerator::expandMethodHandleInvokeCall(TR::TreeTop *tree)
3160
{
3161
TR::Node *ttNode = tree->getNode();
3162
TR::Node* callNode = ttNode->getFirstChild();
3163
TR::TreeTop* prevTree = tree->getPrevTreeTop();
3164
TR::TreeTop* nextTree = tree->getNextTreeTop();
3165
3166
if (comp()->getOption(TR_TraceILGen))
3167
{
3168
traceMsg(comp(), "Found MethodHandle invoke call n%dn %p to expand\n", callNode->getGlobalIndex(), callNode);
3169
traceMsg(comp(), " /--- Tree before expanding n%dn --------------------\n", callNode->getGlobalIndex());
3170
comp()->getDebug()->printWithFixedPrefix(comp()->getOutFile(), ttNode, 1, true, true, " ");
3171
traceMsg(comp(), "\n");
3172
}
3173
3174
int32_t oldBCIndex = _bcIndex;
3175
_bcIndex = callNode->getByteCodeIndex();
3176
3177
// Preserve the NULLCHK
3178
//
3179
TR::TransformUtil::separateNullCheck(comp(), tree, comp()->getOption(TR_TraceILGen));
3180
// Anchor all children
3181
//
3182
for (int i = callNode->getFirstArgumentIndex(); i < callNode->getNumChildren(); i++)
3183
{
3184
TR::Node* child = callNode->getChild(i);
3185
TR::TreeTop *anchorTT = TR::TreeTop::create(comp(), TR::Node::create(TR::treetop, 1, child));
3186
if (comp()->getOption(TR_TraceILGen))
3187
{
3188
traceMsg(comp(), "TreeTop n%dn is created to anchor node n%dn\n", anchorTT->getNode()->getGlobalIndex(), child->getGlobalIndex());
3189
}
3190
tree->insertBefore(anchorTT);
3191
}
3192
3193
if (_invokeHandleCalls &&
3194
_invokeHandleCalls->isSet(_bcIndex))
3195
{
3196
expandInvokeHandle(tree);
3197
}
3198
else if (_invokeHandleGenericCalls &&
3199
_invokeHandleGenericCalls->isSet(_bcIndex))
3200
{
3201
expandInvokeHandleGeneric(tree);
3202
}
3203
else if (_invokeDynamicCalls &&
3204
_invokeDynamicCalls->isSet(_bcIndex))
3205
{
3206
expandInvokeDynamic(tree);
3207
}
3208
else if (_ilGenMacroInvokeExactCalls &&
3209
_ilGenMacroInvokeExactCalls->isSet(_bcIndex))
3210
{
3211
expandInvokeExact(tree);
3212
}
3213
else
3214
{
3215
TR_ASSERT(comp(), "Unexpected MethodHandle invoke call at n%dn %p", callNode->getGlobalIndex(), callNode);
3216
}
3217
3218
// Specialize MethodHandle.invokeExact if the receiver handle is a known object
3219
TR::Node* methodHandle = callNode->getFirstArgument();
3220
if (methodHandle->getOpCode().hasSymbolReference()
3221
&& methodHandle->getSymbolReference()->hasKnownObjectIndex())
3222
{
3223
TR::KnownObjectTable::Index index = methodHandle->getSymbolReference()->getKnownObjectIndex();
3224
uintptr_t* objectLocation = comp()->getKnownObjectTable()->getPointerLocation(index);
3225
TR::TransformUtil::specializeInvokeExactSymbol(comp(), callNode, objectLocation);
3226
}
3227
3228
_bcIndex = oldBCIndex;
3229
3230
if (comp()->getOption(TR_TraceILGen))
3231
{
3232
traceMsg(comp(), " /--- Trees after expanding n%dn --------------------\n", callNode->getGlobalIndex());
3233
TR::TreeTop *tt = prevTree->getNextTreeTop();
3234
do
3235
{
3236
comp()->getDebug()->printWithFixedPrefix(comp()->getOutFile(), tt->getNode(), 1, true, true, " ");
3237
traceMsg(comp(), "\n");
3238
tt = tt->getNextTreeTop();
3239
} while( tt != nextTree);
3240
}
3241
}
3242
3243