Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/optimizer/J9RecognizedCallTransformer.cpp
6000 views
1
/*******************************************************************************
2
* Copyright (c) 2017, 2022 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21
*******************************************************************************/
22
23
#include "optimizer/RecognizedCallTransformer.hpp"
24
25
#include "compile/ResolvedMethod.hpp"
26
#include "env/CompilerEnv.hpp"
27
#include "env/VMJ9.h"
28
#include "env/jittypes.h"
29
#include "il/Block.hpp"
30
#include "il/Node.hpp"
31
#include "il/Node_inlines.hpp"
32
#include "il/StaticSymbol.hpp"
33
#include "il/TreeTop.hpp"
34
#include "il/TreeTop_inlines.hpp"
35
#include "il/ILOpCodes.hpp"
36
#include "il/ILOps.hpp"
37
#include "ilgen/IlGenRequest.hpp"
38
#include "ilgen/IlGeneratorMethodDetails.hpp"
39
#include "ilgen/IlGeneratorMethodDetails_inlines.hpp"
40
#include "optimizer/CallInfo.hpp"
41
#include "optimizer/IdiomRecognitionUtils.hpp"
42
#include "optimizer/Structure.hpp"
43
#include "codegen/CodeGenerator.hpp"
44
#include "optimizer/TransformUtil.hpp"
45
#include "env/j9method.h"
46
#include "optimizer/Optimization_inlines.hpp"
47
48
void J9::RecognizedCallTransformer::processIntrinsicFunction(TR::TreeTop* treetop, TR::Node* node, TR::ILOpCodes opcode)
49
{
50
TR::Node::recreate(node, opcode);
51
}
52
53
void J9::RecognizedCallTransformer::processConvertingUnaryIntrinsicFunction(TR::TreeTop* treetop, TR::Node* node, TR::ILOpCodes argConvertOpcode, TR::ILOpCodes opcode, TR::ILOpCodes resultConvertOpcode)
54
{
55
TR::Node* actualArg = TR::Node::create(argConvertOpcode, 1, node->getFirstChild());
56
TR::Node* actualResult = TR::Node::create(opcode, 1, actualArg);
57
58
TR::Node::recreate(node, resultConvertOpcode);
59
node->getFirstChild()->decReferenceCount();
60
node->setAndIncChild(0, actualResult);
61
}
62
63
void J9::RecognizedCallTransformer::process_java_lang_Class_IsAssignableFrom(TR::TreeTop* treetop, TR::Node* node)
64
{
65
auto toClass = node->getChild(0);
66
auto fromClass = node->getChild(1);
67
auto nullchk = comp()->getSymRefTab()->findOrCreateNullCheckSymbolRef(comp()->getMethodSymbol());
68
treetop->insertBefore(TR::TreeTop::create(comp(), TR::Node::createWithSymRef(TR::NULLCHK, 1, 1, TR::Node::create(node, TR::PassThrough, 1, toClass), nullchk)));
69
treetop->insertBefore(TR::TreeTop::create(comp(), TR::Node::createWithSymRef(TR::NULLCHK, 1, 1, TR::Node::create(node, TR::PassThrough, 1, fromClass), nullchk)));
70
71
TR::Node::recreate(treetop->getNode(), TR::treetop);
72
node->setSymbolReference(comp()->getSymRefTab()->findOrCreateRuntimeHelper(TR_checkAssignable));
73
node->setAndIncChild(0, TR::Node::createWithSymRef(TR::aloadi, 1, 1, toClass, comp()->getSymRefTab()->findOrCreateClassFromJavaLangClassSymbolRef()));
74
node->setAndIncChild(1, TR::Node::createWithSymRef(TR::aloadi, 1, 1, fromClass, comp()->getSymRefTab()->findOrCreateClassFromJavaLangClassSymbolRef()));
75
node->swapChildren();
76
77
toClass->recursivelyDecReferenceCount();
78
fromClass->recursivelyDecReferenceCount();
79
}
80
81
// This methods inlines a call node that calls StringCoding.encodeASCII into an if-diamond. The forward path of the
82
// if-diamond inlines the call using a compiler intrinsic and the fallback path reverts back to calling the method traditionally.
83
void J9::RecognizedCallTransformer::process_java_lang_StringCoding_encodeASCII(TR::TreeTop* treetop, TR::Node* node)
84
{
85
TR_J9VMBase *fej9 = static_cast<TR_J9VMBase*>(comp()->fe());
86
TR_OpaqueClassBlock *stringClass = comp()->getStringClassPointer();
87
if (!stringClass || !fej9->getByteArrayClass())
88
{
89
return;
90
}
91
uint32_t *latin1FieldAddress = (uint32_t *)fej9->getStaticFieldAddress(stringClass, (unsigned char *) "LATIN1", 6, (unsigned char *)"B", 1);
92
TR::CFG *cfg = comp()->getFlowGraph();
93
94
TR::Node *coderNode = node->getChild(0);
95
TR::Node *sourceArrayNode = node->getChild(1);
96
97
// Anchor the source array node as we need it in the fallthrough block.
98
anchorNode(sourceArrayNode, treetop);
99
100
// Now generate the ificmpne tree and insert it before the original call tree.
101
// Note that *latin1FieldAddress will be correct for AOT compilations as well because String.LATIN1 is a final static field with
102
// a constant initializer. This means its value is determined by the ROM class of String, and therefore when the String class chain validation succeeds
103
// on AOT load, the value is guaranteed to be the same as the one we see during AOT compilation.
104
TR::Node *constNode = TR::Node::iconst(node, ((TR_J9VM *)fej9)->dereferenceStaticFinalAddress(latin1FieldAddress, TR::Int32).dataInt32Bit);
105
TR::Node *ifCmpNode = TR::Node::createif(TR::ificmpne, coderNode, constNode);
106
TR::TreeTop *ifCmpTreeTop = TR::TreeTop::create(comp(), treetop->getPrevTreeTop(), ifCmpNode);
107
108
// Split the current block right before the call (or after the ificmpne).
109
TR::Block *ifCmpBlock = ifCmpTreeTop->getEnclosingBlock();
110
TR::Block *fallbackPathBlock = ifCmpBlock->split(treetop, cfg, true /* fixUpCommoning */, true /* copyExceptionSuccessors */);
111
// Then split again to create the tail block
112
TR::Block *tailBlock = fallbackPathBlock->split(treetop->getNextTreeTop(), cfg, true /* fixUpCommoning */, true /* copyExceptionSuccessors */);
113
114
// Now we have the originalBlock, the fallback block and the merge block (tailBlock). The call result will be an astore.
115
// If the nodes in the above blocks were uncommoned as expected, then the treetop after the call node should be an astore to a temp slot.
116
// So assert that it is, and then grab a reference to the temp slot so we can store to it ourselves in the forward path.
117
// Note that we can rely on the call result having been used in a later tree since encodeASCII represents a private method whose call sites we can inspect
118
// and because this transformation happens very early as part of ilgen opts
119
TR::Node *resultStoreNode = treetop->getNextTreeTop()->getNode();
120
TR::SymbolReference *tempSlotForCallResult = NULL;
121
TR_ASSERT_FATAL(resultStoreNode, "Treetop after call is not an astore");
122
TR_ASSERT_FATAL(resultStoreNode->getOpCode().getOpCodeValue() == TR::astore, "Treetop after call must be an astore to a temp!");
123
tempSlotForCallResult = resultStoreNode->getSymbolReference();
124
TR_ASSERT_FATAL(tempSlotForCallResult, "Symbol reference for store node can't be null\n");
125
TR_ASSERT_FATAL(resultStoreNode->getChild(0) == node, "The value stored must be the call result");
126
127
// Ready to create our fallthrough block now. Connect it to ifCmpTreeTop, and then split it with nodes commoned.
128
int32_t byteArrayType = fej9->getNewArrayTypeFromClass(fej9->getByteArrayClass());
129
130
// Create a new arraylength node.
131
sourceArrayNode = node->getChild(1)->duplicateTree();
132
TR::Node *lenNode = TR::Node::create(node, TR::arraylength, 1, sourceArrayNode);
133
134
// Create the destination array
135
TR::Node *destinationArrayNode = TR::Node::createWithSymRef(node, TR::newarray, 2, comp()->getSymRefTab()->findOrCreateNewArraySymbolRef(node->getSymbolReference()->getOwningMethodSymbol(comp())));
136
destinationArrayNode->setAndIncChild(0, lenNode);
137
destinationArrayNode->setAndIncChild(1, TR::Node::iconst(byteArrayType));
138
TR::TreeTop *destinationArrayTreeTop = TR::TreeTop::create(comp(), TR::Node::create(node, TR::treetop, 1, destinationArrayNode));
139
ifCmpTreeTop->insertAfter(destinationArrayTreeTop);
140
destinationArrayNode->setCanSkipZeroInitialization(true);
141
destinationArrayNode->setIsNonNull(true);
142
143
// We now have the length node, and also the destination array. Now we create an encodeASCIISymbol node to do the encoding operation.
144
/*
145
// tree looks as follows:
146
// call encodeASCIISymbol
147
// input ptr
148
// output ptr
149
// input length (in elements)
150
*/
151
152
TR::SymbolReference *methodSymRef = comp()->getSymRefTab()->findOrCreateEncodeASCIISymbolRef();
153
TR::Node *encodeASCIINode = TR::Node::createWithSymRef(TR::call, 3, methodSymRef);
154
155
TR::Node *newInputNode = NULL;
156
TR::Node *arrayHeaderSizeNode = NULL;
157
TR::Node *newOutputNode = NULL;
158
159
if (comp()->target().is64Bit())
160
{
161
newInputNode = TR::Node::create(sourceArrayNode, TR::aladd, 2);
162
newOutputNode = TR::Node::create(destinationArrayNode, TR::aladd, 2);
163
arrayHeaderSizeNode = TR::Node::lconst((int64_t)TR::Compiler->om.contiguousArrayHeaderSizeInBytes());
164
}
165
else
166
{
167
newInputNode = TR::Node::create(sourceArrayNode, TR::aiadd, 2);
168
newOutputNode = TR::Node::create(destinationArrayNode, TR::aiadd, 2);
169
arrayHeaderSizeNode = TR::Node::iconst((int32_t)TR::Compiler->om.contiguousArrayHeaderSizeInBytes());
170
}
171
172
newInputNode->setAndIncChild(0, sourceArrayNode);
173
newInputNode->setAndIncChild(1, arrayHeaderSizeNode);
174
encodeASCIINode->setAndIncChild(0, newInputNode);
175
176
newOutputNode->setAndIncChild(0, destinationArrayNode);
177
newOutputNode->setAndIncChild(1, arrayHeaderSizeNode);
178
encodeASCIINode->setAndIncChild(1, newOutputNode);
179
180
encodeASCIINode->setAndIncChild(2, lenNode);
181
182
TR::TreeTop *encodeASCIITreeTop = TR::TreeTop::create(comp(), TR::Node::create(node, TR::treetop, 1, encodeASCIINode));
183
destinationArrayTreeTop->insertAfter(encodeASCIITreeTop);
184
185
TR::Node *storeNode = TR::Node::createWithSymRef(node, TR::astore, 1, destinationArrayNode, tempSlotForCallResult);
186
TR::TreeTop *storeNodeTreeTop = TR::TreeTop::create(comp(), encodeASCIITreeTop, storeNode);
187
188
// Now split starting from destinationArrayTreeTop and uncommon the nodes..
189
TR::Block *fallthroughBlock = destinationArrayTreeTop->getEnclosingBlock()->split(destinationArrayTreeTop, cfg, true /* fixUpCommoning */, true /* copyExceptionSuccessors */);
190
191
// Now create a node to go to the merge (i.e. tail) block.
192
TR::Node *gotoNode = TR::Node::create(node, TR::Goto);
193
TR::TreeTop *gotoTree = TR::TreeTop::create(comp(), gotoNode, NULL, NULL);
194
gotoNode->setBranchDestination(tailBlock->getEntry());
195
fallthroughBlock->getExit()->insertBefore(gotoTree);
196
197
// Now we have fallthrough block, fallback block and tail/merge block. Let's set the ifcmp's destination to the fallback block, and update the CFG as well.
198
ifCmpNode->setBranchDestination(fallbackPathBlock->getEntry());
199
cfg->addEdge(ifCmpTreeTop->getEnclosingBlock(), fallbackPathBlock);
200
cfg->addEdge(fallthroughBlock, tailBlock);
201
cfg->removeEdge(fallthroughBlock, fallbackPathBlock);
202
}
203
204
void J9::RecognizedCallTransformer::process_java_lang_StringUTF16_toBytes(TR::TreeTop* treetop, TR::Node* node)
205
{
206
TR_J9VMBase* fej9 = static_cast<TR_J9VMBase*>(comp()->fe());
207
208
TR::Node* valueNode = node->getChild(0);
209
TR::Node* offNode = node->getChild(1);
210
TR::Node* lenNode = node->getChild(2);
211
212
anchorAllChildren(node, treetop);
213
prepareToReplaceNode(node);
214
215
int32_t byteArrayType = fej9->getNewArrayTypeFromClass(fej9->getByteArrayClass());
216
217
TR::Node::recreateWithoutProperties(node, TR::newarray, 2,
218
TR::Node::create(TR::ishl, 2,
219
lenNode,
220
TR::Node::iconst(1)),
221
TR::Node::iconst(byteArrayType),
222
223
getSymRefTab()->findOrCreateNewArraySymbolRef(node->getSymbolReference()->getOwningMethodSymbol(comp())));
224
225
TR::Node* newByteArrayNode = node;
226
newByteArrayNode->setCanSkipZeroInitialization(true);
227
newByteArrayNode->setIsNonNull(true);
228
229
TR::Node* newCallNode = TR::Node::createWithSymRef(node, TR::call, 5,
230
getSymRefTab()->methodSymRefFromName(comp()->getMethodSymbol(), "java/lang/String", "decompressedArrayCopy", "([CI[BII)V", TR::MethodSymbol::Static));
231
newCallNode->setAndIncChild(0, valueNode);
232
newCallNode->setAndIncChild(1, offNode);
233
newCallNode->setAndIncChild(2, newByteArrayNode);
234
newCallNode->setAndIncChild(3, TR::Node::iconst(0));
235
newCallNode->setAndIncChild(4, lenNode);
236
237
treetop->insertAfter(TR::TreeTop::create(comp(), TR::Node::create(node, TR::treetop, 1, newCallNode)));
238
}
239
240
void J9::RecognizedCallTransformer::process_java_lang_StrictMath_and_Math_sqrt(TR::TreeTop* treetop, TR::Node* node)
241
{
242
TR::Node* valueNode = node->getLastChild();
243
244
anchorAllChildren(node, treetop);
245
prepareToReplaceNode(node);
246
247
TR::Node::recreate(node, TR::dsqrt);
248
node->setNumChildren(1);
249
node->setAndIncChild(0, valueNode);
250
251
TR::TransformUtil::removeTree(comp(), treetop);
252
}
253
/*
254
Transform an Unsafe atomic call to diamonds with equivalent semantics
255
256
yes
257
isObjectNull ------------------------------------------>
258
| |
259
| no |
260
| yes |
261
isNotLowTagged ---------------------------------------->
262
| |
263
| no |
264
| no |
265
isFinal ----------------------> |
266
| | |
267
| yes | |
268
| | |
269
call the calculate address calculate address
270
original method for static field for instance field
271
| | and absolute address
272
| | |
273
| |________________________|
274
| |
275
| xcall atomic method helper
276
| |
277
|_____________________________________|
278
|
279
program after the original call
280
281
Block before the transformation: ===>
282
283
start Block_A
284
...
285
xcall Unsafe.xxx
286
...
287
end Block_A
288
289
Blocks after the transformation: ===>
290
291
start Block_A
292
...
293
ifacmpeq -> <Block_E>
294
object
295
aconst null
296
end Block_A
297
298
start Block_B
299
iflcmpne -> <Block_E>
300
land
301
lload <offset>
302
lconst J9_SUN_STATIC_FIELD_OFFSET_TAG
303
lconst J9_SUN_STATIC_FIELD_OFFSET_TAG
304
end Block_B
305
306
start Block_C
307
iflcmpeq -> <Block_F>
308
land
309
lload <offset>
310
lconst J9_SUN_FINAL_FIELD_OFFSET_TAG
311
lconst J9_SUN_FINAL_FIELD_OFFSET_TAG
312
end Block_C
313
314
start Block_D
315
astore <object>
316
aloadi ramStaticsFromClass
317
...
318
lstore <offset>
319
land
320
lload <offset>
321
lconst ~J9_SUN_FIELD_OFFSET_MASK
322
end Block_D
323
324
start Block_E
325
xcall atomic method helper
326
aladd
327
aload <object>
328
lload <offset>
329
xload value
330
end Block_E
331
332
...
333
334
start Block_F
335
call jitReportFinalFieldModified
336
go to <Block_E>
337
end Block_F
338
*/
339
void J9::RecognizedCallTransformer::processUnsafeAtomicCall(TR::TreeTop* treetop, TR::SymbolReferenceTable::CommonNonhelperSymbol helper, bool needsNullCheck)
340
{
341
bool enableTrace = trace();
342
bool isNotStaticField = !strncmp(comp()->getCurrentMethod()->classNameChars(), "java/util/concurrent/atomic/", strlen("java/util/concurrent/atomic/"));
343
bool fixupCommoning = true;
344
TR::Node* unsafeCall = treetop->getNode()->getFirstChild();
345
TR::Node* objectNode = unsafeCall->getChild(1);
346
TR::Node* offsetNode = unsafeCall->getChild(2);
347
TR::Node* address = NULL;
348
349
// Preserve null check on the unsafe object
350
if (treetop->getNode()->getOpCode().isNullCheck())
351
{
352
TR::Node *passthrough = TR::Node::create(unsafeCall, TR::PassThrough, 1);
353
passthrough->setAndIncChild(0, unsafeCall->getFirstChild());
354
TR::Node * checkNode = TR::Node::createWithSymRef(treetop->getNode(), TR::NULLCHK, 1, passthrough, treetop->getNode()->getSymbolReference());
355
treetop->insertBefore(TR::TreeTop::create(comp(), checkNode));
356
TR::Node::recreate(treetop->getNode(), TR::treetop);
357
if (enableTrace)
358
traceMsg(comp(), "Created node %p to preserve NULLCHK on unsafe call %p\n", checkNode, unsafeCall);
359
}
360
361
if (isNotStaticField)
362
{
363
// It is safe to skip diamond, the address can be calculated directly via [object+offset]
364
address = comp()->target().is32Bit() ? TR::Node::create(TR::aiadd, 2, objectNode, TR::Node::create(TR::l2i, 1, offsetNode)) :
365
TR::Node::create(TR::aladd, 2, objectNode, offsetNode);
366
if (enableTrace)
367
traceMsg(comp(), "Field is not static, use the object and offset directly\n");
368
}
369
else
370
{
371
// Otherwise, the address is [object+offset] for non-static field,
372
// or [object's ramStaticsFromClass + (offset & ~mask)] for static field
373
374
// Save all the children to temps before splitting the block
375
TR::TransformUtil::createTempsForCall(this, treetop);
376
377
auto cfg = comp()->getMethodSymbol()->getFlowGraph();
378
objectNode = unsafeCall->getChild(1);
379
offsetNode = unsafeCall->getChild(2);
380
381
// Null Check
382
if (needsNullCheck)
383
{
384
auto NULLCHKNode = TR::Node::createWithSymRef(unsafeCall, TR::NULLCHK, 1,
385
TR::Node::create(TR::PassThrough, 1, objectNode->duplicateTree()),
386
comp()->getSymRefTab()->findOrCreateNullCheckSymbolRef(comp()->getMethodSymbol()));
387
treetop->insertBefore(TR::TreeTop::create(comp(), NULLCHKNode));
388
if (enableTrace)
389
traceMsg(comp(), "Created NULLCHK tree %p on the first argument of Unsafe call\n", treetop->getPrevTreeTop());
390
}
391
392
// Test if object is null
393
auto isObjectNullNode = TR::Node::createif(TR::ifacmpeq, objectNode->duplicateTree(), TR::Node::aconst(0), NULL);
394
auto isObjectNullTreeTop = TR::TreeTop::create(comp(), isObjectNullNode);
395
treetop->insertBefore(isObjectNullTreeTop);
396
treetop->getEnclosingBlock()->split(treetop, cfg, fixupCommoning);
397
398
if (enableTrace)
399
traceMsg(comp(), "Created isObjectNull test node n%dn, non-null object will fall through to Block_%d\n", isObjectNullNode->getGlobalIndex(), treetop->getEnclosingBlock()->getNumber());
400
401
// Test if low tag is set
402
auto isNotLowTaggedNode = TR::Node::createif(TR::iflcmpne,
403
TR::Node::create(TR::land, 2, offsetNode->duplicateTree(), TR::Node::lconst(J9_SUN_STATIC_FIELD_OFFSET_TAG)),
404
TR::Node::lconst(J9_SUN_STATIC_FIELD_OFFSET_TAG),
405
NULL);
406
auto isNotLowTaggedTreeTop = TR::TreeTop::create(comp(), isNotLowTaggedNode);
407
treetop->insertBefore(isNotLowTaggedTreeTop);
408
treetop->getEnclosingBlock()->split(treetop, cfg, fixupCommoning);
409
410
if (enableTrace)
411
traceMsg(comp(), "Created isNotLowTagged test node n%dn, static field will fall through to Block_%d\n", isNotLowTaggedNode->getGlobalIndex(), treetop->getEnclosingBlock()->getNumber());
412
413
static char *disableIllegalWriteReport = feGetEnv("TR_DisableIllegalWriteReport");
414
// Test if the call is a write to a static final field
415
if (!disableIllegalWriteReport
416
&& !comp()->getOption(TR_DisableGuardedStaticFinalFieldFolding)
417
&& TR_J9MethodBase::isUnsafePut(unsafeCall->getSymbol()->castToMethodSymbol()->getMandatoryRecognizedMethod()))
418
{
419
// If the field is static final
420
auto isFinalNode = TR::Node::createif(TR::iflcmpeq,
421
TR::Node::create(TR::land, 2, offsetNode->duplicateTree(), TR::Node::lconst(J9_SUN_FINAL_FIELD_OFFSET_TAG)),
422
TR::Node::lconst(J9_SUN_FINAL_FIELD_OFFSET_TAG),
423
NULL /*branchTarget*/);
424
auto isFinalTreeTop = TR::TreeTop::create(comp(), isFinalNode);
425
auto reportFinalFieldModification = TR::TransformUtil::generateReportFinalFieldModificationCallTree(comp(), objectNode->duplicateTree());
426
auto elseBlock = treetop->getEnclosingBlock();
427
TR::TransformUtil::createConditionalAlternatePath(comp(), isFinalTreeTop, reportFinalFieldModification, elseBlock, elseBlock, comp()->getMethodSymbol()->getFlowGraph(), true /*markCold*/);
428
if (enableTrace)
429
{
430
traceMsg(comp(), "Created isFinal test node n%dn, non-final-static field will fall through to Block_%d, final field goes to Block_%d\n",
431
isFinalNode->getGlobalIndex(), treetop->getEnclosingBlock()->getNumber(), reportFinalFieldModification->getEnclosingBlock()->getNumber());
432
}
433
TR::DebugCounter::prependDebugCounter(comp(),
434
TR::DebugCounter::debugCounterName(comp(),
435
"illegalWriteReport/atomic/(%s %s)",
436
comp()->signature(),
437
comp()->getHotnessName(comp()->getMethodHotness())),
438
reportFinalFieldModification->getNextTreeTop());
439
440
}
441
442
// Calculate static address
443
auto objectAdjustmentNode = TR::Node::createWithSymRef(TR::astore, 1, 1,
444
TR::Node::createWithSymRef(TR::aloadi, 1, 1,
445
TR::Node::createWithSymRef(TR::aloadi, 1, 1,
446
objectNode->duplicateTree(),
447
comp()->getSymRefTab()->findOrCreateClassFromJavaLangClassSymbolRef()),
448
comp()->getSymRefTab()->findOrCreateRamStaticsFromClassSymbolRef()),
449
objectNode->getSymbolReference());
450
auto offsetAdjustmentNode = TR::Node::createWithSymRef(TR::lstore, 1, 1,
451
TR::Node::create(TR::land, 2,
452
offsetNode->duplicateTree(),
453
TR::Node::lconst(~J9_SUN_FIELD_OFFSET_MASK)),
454
offsetNode->getSymbolReference());
455
456
if (enableTrace)
457
traceMsg(comp(), "Created node n%dn and n%dn to adjust object and offset for static field\n", objectAdjustmentNode->getGlobalIndex(), offsetAdjustmentNode->getGlobalIndex());
458
459
treetop->insertBefore(TR::TreeTop::create(comp(), objectAdjustmentNode));
460
treetop->insertBefore(TR::TreeTop::create(comp(), offsetAdjustmentNode));
461
treetop->getEnclosingBlock()->split(treetop, cfg, fixupCommoning);
462
463
if (enableTrace)
464
traceMsg(comp(), "Block_%d contains call to atomic method helper, and is the target of isObjectNull and isNotLowTagged tests\n", treetop->getEnclosingBlock()->getNumber());
465
466
// Setup CFG edges
467
isObjectNullNode->setBranchDestination(treetop->getEnclosingBlock()->getEntry());
468
cfg->addEdge(TR::CFGEdge::createEdge(isObjectNullTreeTop->getEnclosingBlock(), treetop->getEnclosingBlock(), comp()->trMemory()));
469
isNotLowTaggedNode->setBranchDestination(treetop->getEnclosingBlock()->getEntry());
470
cfg->addEdge(TR::CFGEdge::createEdge(isNotLowTaggedTreeTop->getEnclosingBlock(), treetop->getEnclosingBlock(), comp()->trMemory()));
471
address = comp()->target().is32Bit() ? TR::Node::create(TR::aiadd, 2, objectNode->duplicateTree(), TR::Node::create(TR::l2i, 1, offsetNode->duplicateTree())) :
472
TR::Node::create(TR::aladd, 2, objectNode->duplicateTree(), offsetNode->duplicateTree());
473
}
474
475
// Transmute the unsafe call to a call to atomic method helper
476
unsafeCall->getChild(0)->recursivelyDecReferenceCount(); // replace unsafe object with the address
477
unsafeCall->setAndIncChild(0, address);
478
unsafeCall->removeChild(2); // remove offset node
479
unsafeCall->removeChild(1); // remove object node
480
unsafeCall->setSymbolReference(comp()->getSymRefTab()->findOrCreateCodeGenInlinedHelper(helper));
481
}
482
483
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
484
485
/** \brief
486
* Constructs signature strings for constructing methods representing computed calls
487
* from the signature of the original INL calls. Adapted from getSignatureForLinkToStatic
488
* in j9method.cpp
489
*
490
* \param extraParamsBefore
491
* the params to be prepended to the original signature
492
*
493
* \param extraParamsAfter
494
* the params to be appended to the original signature
495
*
496
* \param comp
497
* the current compilation
498
*
499
* \param origSignature
500
* the original signautre
501
*
502
* \param signatureLength
503
* the constructed signature length
504
*
505
* \return
506
* static char * the constructed signature
507
*/
508
509
static char *
510
getSignatureForComputedCall(
511
const char * const extraParamsBefore,
512
const char * const extraParamsAfter,
513
TR::Compilation* comp,
514
const char * const origSignature,
515
int32_t &signatureLength)
516
{
517
const size_t extraParamsLength = strlen(extraParamsBefore) + strlen(extraParamsAfter);
518
519
const int origSignatureLength = strlen(origSignature);
520
signatureLength = origSignatureLength + extraParamsLength;
521
522
const int32_t signatureAllocSize = signatureLength + 28; // +1 for NULL terminator
523
char * computedCallSignature =
524
(char *)comp->trMemory()->allocateMemory(signatureAllocSize, heapAlloc);
525
526
// Can't simply strchr() for ')' because that can appear within argument
527
// types, in particular within class names. It's necessary to parse the
528
// signature.
529
const char * const paramsStart = origSignature + 1;
530
const char * paramsEnd = paramsStart;
531
const char * previousParam = paramsEnd;
532
const char * returnType = NULL;
533
while (*paramsEnd != ')')
534
{
535
paramsEnd = nextSignatureArgument(paramsEnd);
536
if (!strncmp(paramsEnd, "Ljava/lang/invoke/MemberName;", 29)) // MemberName object must be discarded
537
{
538
returnType = nextSignatureArgument(paramsEnd) + 1;
539
break;
540
}
541
}
542
543
if (!returnType) returnType = paramsEnd + 1;
544
const char * const returnTypeEnd = nextSignatureArgument(returnType);
545
546
// Put together the new signature.
547
snprintf(
548
computedCallSignature,
549
signatureAllocSize,
550
"(%s%.*s%s)%.*s",
551
extraParamsBefore,
552
(int)(paramsEnd - paramsStart),
553
paramsStart,
554
extraParamsAfter,
555
(int)(returnTypeEnd - returnType),
556
returnType);
557
558
return computedCallSignature;
559
}
560
561
void J9::RecognizedCallTransformer::process_java_lang_invoke_MethodHandle_invokeBasic(TR::TreeTop * treetop, TR::Node* node)
562
{
563
TR_J9VMBase* fej9 = static_cast<TR_J9VMBase*>(comp()->fe());
564
TR::TransformUtil::separateNullCheck(comp(), treetop, true);
565
TR::Node * inlCallNode = node->duplicateTree(false);
566
TR::list<TR::SymbolReference *>* argsList = new (comp()->trStackMemory()) TR::list<TR::SymbolReference*>(getTypedAllocator<TR::SymbolReference*>(comp()->allocator()));
567
for (int i = 0; i < node->getNumChildren(); i++)
568
{
569
TR::Node * currentChild = node->getChild(i);
570
TR::SymbolReference *newSymbolReference = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(), currentChild->getDataType());
571
argsList->push_back(newSymbolReference);
572
TR::Node * storeNode = TR::Node::createStore(node, newSymbolReference, currentChild);
573
treetop->insertBefore(TR::TreeTop::create(comp(),storeNode));
574
inlCallNode->setAndIncChild(i, TR::Node::createLoad(node, newSymbolReference));
575
currentChild->recursivelyDecReferenceCount();
576
}
577
578
TR::Node* mhNode = TR::Node::createLoad(node, argsList->front()); // the first arg of invokeBasic call is the receiver MethodHandle object
579
// load MethodHandle.form, which is the LambdaForm object
580
uint32_t offset = fej9->getInstanceFieldOffsetIncludingHeader("Ljava/lang/invoke/MethodHandle;", "form", "Ljava/lang/invoke/LambdaForm;", comp()->getCurrentMethod());
581
TR::SymbolReference * lambdaFormSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(comp()->getMethodSymbol(),
582
TR::Symbol::Java_lang_invoke_MethodHandle_form,
583
TR::Address,
584
offset,
585
false,
586
false,
587
true,
588
"java/lang/invoke/MethodHandle.form Ljava/lang/invoke/LambdaForm;");
589
TR::Node * lambdaFormNode = TR::Node::createWithSymRef(node, comp()->il.opCodeForIndirectLoad(TR::Address), 1 , mhNode, lambdaFormSymRef);
590
lambdaFormNode->setIsNonNull(true);
591
// load from lambdaForm.vmEntry, which is the MemberName object
592
offset = fej9->getInstanceFieldOffsetIncludingHeader("Ljava/lang/invoke/LambdaForm;", "vmentry", "Ljava/lang/invoke/MemberName;", comp()->getCurrentMethod());
593
TR::SymbolReference * memberNameSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(comp()->getMethodSymbol(),
594
TR::Symbol::Java_lang_invoke_LambdaForm_vmentry,
595
TR::Address,
596
offset,
597
false,
598
false,
599
true,
600
"java/lang/invoke/LambdaForm.vmentry Ljava/lang/invoke/MemberName;");
601
TR::Node * memberNameNode = TR::Node::createWithSymRef(node, comp()->il.opCodeForIndirectLoad(TR::Address), 1, lambdaFormNode, memberNameSymRef);
602
// load from membername.vmTarget, which is the J9Method
603
TR::SymbolReference * vmTargetSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(comp()->getMethodSymbol(),
604
TR::Symbol::Java_lang_invoke_MemberName_vmtarget,
605
TR::Address,
606
fej9->getVMTargetOffset(),
607
false,
608
false,
609
true,
610
"java/lang/invoke/MemberName.vmtarget J");
611
vmTargetSymRef->getSymbol()->setNotCollected();
612
TR::Node * vmTargetNode = TR::Node::createWithSymRef(node, TR::aloadi, 1, memberNameNode, vmTargetSymRef);
613
processVMInternalNativeFunction(treetop, node, vmTargetNode, argsList, inlCallNode);
614
}
615
616
void J9::RecognizedCallTransformer::process_java_lang_invoke_MethodHandle_linkToStaticSpecial(TR::TreeTop* treetop, TR::Node* node)
617
{
618
TR_J9VMBase* fej9 = static_cast<TR_J9VMBase*>(comp()->fe());
619
TR::TransformUtil::separateNullCheck(comp(), treetop, true);
620
TR::Node * inlCallNode = node->duplicateTree(false);
621
TR::list<TR::SymbolReference *>* argsList = new (comp()->trStackMemory()) TR::list<TR::SymbolReference*>(getTypedAllocator<TR::SymbolReference*>(comp()->allocator()));
622
for (int i = 0; i < node->getNumChildren(); i++)
623
{
624
TR::Node * currentChild = node->getChild(i);
625
TR::SymbolReference *newSymbolReference = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(), currentChild->getDataType());
626
argsList->push_back(newSymbolReference);
627
TR::Node * storeNode = TR::Node::createStore(node, newSymbolReference, currentChild);
628
treetop->insertBefore(TR::TreeTop::create(comp(),storeNode));
629
inlCallNode->setAndIncChild(i, TR::Node::createLoad(node, newSymbolReference));
630
currentChild->recursivelyDecReferenceCount();
631
}
632
// load from membername.vmTarget, which is the J9Method
633
TR::Node* mnNode = TR::Node::createLoad(node, argsList->back());
634
TR::SymbolReference * vmTargetSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(comp()->getMethodSymbol(),
635
TR::Symbol::Java_lang_invoke_MemberName_vmtarget,
636
TR::Address,
637
fej9->getVMTargetOffset(),
638
false,
639
false,
640
true,
641
"java/lang/invoke/MemberName.vmtarget J");
642
vmTargetSymRef->getSymbol()->setNotCollected();
643
TR::Node * vmTargetNode = TR::Node::createWithSymRef(node, TR::aloadi, 1, mnNode, vmTargetSymRef);
644
vmTargetNode->setIsNonNull(true);
645
argsList->pop_back(); // MemberName is not required when dispatching directly to the jitted method address
646
processVMInternalNativeFunction(treetop, node, vmTargetNode, argsList, inlCallNode);
647
}
648
649
void J9::RecognizedCallTransformer::processVMInternalNativeFunction(TR::TreeTop* treetop, TR::Node* node, TR::Node* vmTargetNode, TR::list<TR::SymbolReference *>* argsList, TR::Node* inlCallNode)
650
{
651
TR::SymbolReference *extraField = comp()->getSymRefTab()->findOrCreateJ9MethodExtraFieldSymbolRef(offsetof(struct J9Method, extra));
652
TR::Node *extra = TR::Node::createWithSymRef(node, comp()->il.opCodeForIndirectLoad(extraField->getSymbol()->getDataType()), 1, vmTargetNode, extraField);
653
TR::SymbolReference *extraTempSlotSymRef = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(),extraField->getSymbol()->getDataType());
654
treetop->insertBefore(TR::TreeTop::create(comp(), TR::Node::createStore(node, extraTempSlotSymRef, extra)));
655
656
TR::ILOpCodes xcmpne = comp()->target().is64Bit()? TR::iflcmpne : TR::ificmpne;
657
TR::ILOpCodes xand = comp()->target().is64Bit()? TR::land : TR::iand;
658
TR::Node *zero = comp()->target().is64Bit()? TR::Node::lconst(node, 0) : TR::Node::iconst(node, 0);
659
TR::Node *mask = comp()->target().is64Bit()? TR::Node::lconst(node, J9_STARTPC_NOT_TRANSLATED) : TR::Node::iconst(node, J9_STARTPC_NOT_TRANSLATED);
660
661
TR::Node* isCompiledNode = TR::Node::createif(xcmpne,
662
TR::Node::create(xand, 2, TR::Node::createLoad(node, extraTempSlotSymRef), mask),
663
zero,
664
NULL);
665
isCompiledNode->copyByteCodeInfo(node);
666
TR::TreeTop * cmpCheckTreeTop = TR::TreeTop::create(self()->comp(), isCompiledNode);
667
668
TR::Node *jitAddress;
669
if (comp()->target().cpu.isI386())
670
{
671
jitAddress = TR::Node::create(TR::i2l, 1, TR::Node::createLoad(node, extraTempSlotSymRef));
672
}
673
else
674
{
675
TR::SymbolReference *linkageInfoSymRef = comp()->getSymRefTab()->findOrCreateStartPCLinkageInfoSymbolRef(-4);
676
TR::ILOpCodes x2a = comp()->target().is64Bit()? TR::l2a : TR::i2a;
677
TR::Node *linkageInfo = TR::Node::createWithSymRef(TR::iloadi, 1, 1, TR::Node::create(x2a, 1, TR::Node::createLoad(node, extraTempSlotSymRef)), linkageInfoSymRef);
678
TR::Node *jitEntryOffset = TR::Node::create(TR::ishr, 2, linkageInfo, TR::Node::iconst(node, 16));
679
if (comp()->target().is64Bit())
680
jitAddress = TR::Node::create(TR::ladd, 2, TR::Node::createLoad(node, extraTempSlotSymRef), TR::Node::create(TR::i2l, 1, jitEntryOffset));
681
else
682
jitAddress = TR::Node::create(TR::iadd, 2, TR::Node::createLoad(node, extraTempSlotSymRef), jitEntryOffset);
683
}
684
TR_J9VMBase* fej9 = static_cast<TR_J9VMBase*>(comp()->fe());
685
TR_OpaqueMethodBlock *dummyInvoke = fej9->getMethodFromName("com/ibm/jit/JITHelpers", "dispatchComputedStaticCall", "()V");
686
int signatureLength;
687
char * signature = getSignatureForComputedCall(
688
"J",
689
"",
690
comp(),
691
node->getSymbol()->castToMethodSymbol()->getMethod()->signatureChars(),
692
signatureLength);
693
694
// construct a dummy resolved method
695
TR::ResolvedMethodSymbol * owningMethodSymbol = node->getSymbolReference()->getOwningMethodSymbol(comp());
696
TR_ResolvedMethod * dummyMethod = fej9->createResolvedMethodWithSignature(comp()->trMemory(),dummyInvoke, NULL, signature,signatureLength, owningMethodSymbol->getResolvedMethod());
697
TR::SymbolReference * computedCallSymbol = comp()->getSymRefTab()->findOrCreateMethodSymbol(owningMethodSymbol->getResolvedMethodIndex(), -1, dummyMethod, TR::MethodSymbol::ComputedStatic);
698
699
uint32_t numComputedCallArgs = argsList->size() + 1;
700
TR::Node * computedCallNode = TR::Node::createWithSymRef(node, node->getSymbol()->castToMethodSymbol()->getMethod()->indirectCallOpCode(),numComputedCallArgs, computedCallSymbol);
701
computedCallNode->setAndIncChild(0,jitAddress); // first arguments of computed calls is the method address to jump to
702
int32_t child_i = 1;
703
for (auto symRefIt = argsList->begin(); symRefIt != argsList->end(); ++symRefIt)
704
{
705
TR::SymbolReference * currentArg = *symRefIt;
706
computedCallNode->setAndIncChild(child_i, TR::Node::createLoad(node, currentArg));
707
child_i++;
708
}
709
TR::TreeTop * computedCallTreeTop = TR::TreeTop::create(comp(), TR::Node::create(node, TR::treetop, 1, computedCallNode));
710
TR::RecognizedMethod rm = node->getSymbol()->castToMethodSymbol()->getMandatoryRecognizedMethod();
711
TR::Node *nullChkNode = NULL;
712
if (rm == TR::java_lang_invoke_MethodHandle_linkToSpecial || rm == TR::java_lang_invoke_MethodHandle_linkToVirtual)
713
{
714
TR::Node *passthroughNode = TR::Node::create(node, TR::PassThrough, 1);
715
passthroughNode->setAndIncChild(0, TR::Node::createLoad(node, argsList->front()));
716
TR::SymbolReference *symRef = comp()->getSymRefTab()->findOrCreateNullCheckSymbolRef(comp()->getMethodSymbol());
717
nullChkNode = TR::Node::createWithSymRef(TR::NULLCHK, 1, 1, passthroughNode, symRef);
718
}
719
720
TR::TreeTop * inlCallTreeTop = TR::TreeTop::create(comp(), TR::Node::create(node, TR::treetop, 1, inlCallNode)); // original treetop gets deleted by createDiamondForCall
721
TR::TransformUtil::createDiamondForCall(this, treetop, cmpCheckTreeTop, inlCallTreeTop, computedCallTreeTop, false, false);
722
if (nullChkNode) computedCallTreeTop->insertBefore(TR::TreeTop::create(comp(), nullChkNode));
723
_processedINLCalls->set(inlCallNode->getGlobalIndex());
724
}
725
726
void J9::RecognizedCallTransformer::process_java_lang_invoke_MethodHandle_linkToVirtual(TR::TreeTop * treetop, TR::Node * node)
727
{
728
TR_J9VMBase* fej9 = static_cast<TR_J9VMBase*>(comp()->fe());
729
TR::Node * placeholderINLCallNode = node->duplicateTree(false); // this will be eventually removed once the second diamond is created
730
TR::Node* duplicatedINLCallNode = node->duplicateTree(false);
731
TR::list<TR::SymbolReference *>* argsList = new (comp()->trStackMemory()) TR::list<TR::SymbolReference*>(getTypedAllocator<TR::SymbolReference*>(comp()->allocator()));
732
for (int i = 0; i < node->getNumChildren(); i++)
733
{
734
TR::Node * currentChild = node->getChild(i);
735
TR::SymbolReference *newSymbolReference = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(), currentChild->getDataType());
736
newSymbolReference->getSymbol()->setNotCollected();
737
argsList->push_back(newSymbolReference);
738
TR::Node * storeNode = TR::Node::createStore(node, newSymbolReference, currentChild);
739
treetop->insertBefore(TR::TreeTop::create(comp(),storeNode));
740
placeholderINLCallNode->setAndIncChild(i, TR::Node::createLoad(node, newSymbolReference));
741
duplicatedINLCallNode->setAndIncChild(i, TR::Node::createLoad(node, newSymbolReference));
742
currentChild->recursivelyDecReferenceCount();
743
currentChild->recursivelyDecReferenceCount(); // ref count has to be decremented twice as there were two duplicates of the parent made
744
}
745
746
TR::SymbolReference *receiverSymRef = argsList->front();
747
TR::SymbolReference *mnSymRef = argsList->back();
748
749
// -------- construct trees to obtain and check if vTableIndex > 0 --------
750
// get JIT Vtable index from membername.vmindex
751
TR::SymbolReference* vmindexSymRef = comp()->getSymRefTab()->findOrFabricateShadowSymbol(comp()->getMethodSymbol(),
752
TR::Symbol::Java_lang_invoke_MemberName_vmindex,
753
TR::Address,
754
fej9->getVMIndexOffset(),
755
false,
756
false,
757
true,
758
"java/lang/invoke/MemberName.vmindex J");
759
vmindexSymRef->getSymbol()->setNotCollected();
760
761
// construct trees to check if vtable index is zero (NOT MemberName.vmindex, but MN.vmindex.vtableindex). if zero, then call will be dispatched similar to linkToStatic.
762
TR::Node * j9JNIMethodIdNode = TR::Node::createWithSymRef(node, TR::aloadi, 1, TR::Node::createLoad(node, mnSymRef), vmindexSymRef);
763
TR::SymbolReference* vtableIndexSymRef = comp()->getSymRefTab()->findOrCreateJ9JNIMethodIDvTableIndexFieldSymbol(offsetof(struct J9JNIMethodID, vTableIndex));
764
vtableIndexSymRef->getSymbol()->setNotCollected();
765
TR::Node* vtableIndexNode = TR::Node::createWithSymRef(node, comp()->il.opCodeForIndirectLoad(vtableIndexSymRef->getSymbol()->getDataType()), 1, j9JNIMethodIdNode , vtableIndexSymRef);
766
TR::SymbolReference* vtableOffsetTempSlotSymRef = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(),vtableIndexNode->getSymbol()->getDataType());
767
vtableOffsetTempSlotSymRef->getSymbol()->setNotCollected();
768
treetop->insertBefore(TR::TreeTop::create(comp(), TR::Node::createStore(node, vtableOffsetTempSlotSymRef, vtableIndexNode)));
769
TR::ILOpCodes ifxcmpne = comp()->target().is64Bit()? TR::iflcmpne : TR::ificmpne;
770
TR::Node *zero = comp()->target().is64Bit()? TR::Node::lconst(node, 0) : TR::Node::iconst(node, 0);
771
772
TR::Node* vTableOffsetIsNotZero = TR::Node::createif(ifxcmpne,
773
TR::Node::createLoad(node, vtableOffsetTempSlotSymRef),
774
zero,
775
NULL);
776
TR::TreeTop* vtableOffsetIsNotZeroTreeTop = TR::TreeTop::create(comp(), vTableOffsetIsNotZero);
777
778
// -------- construct trees for path to take when vtable index > 0 --------
779
780
// construct a dummy "resolved method" for dispatch virtual:
781
TR_OpaqueMethodBlock *dummyInvoke = fej9->getMethodFromName("com/ibm/jit/JITHelpers", "dispatchVirtual", "()V");
782
int signatureLength;
783
char * signature = getSignatureForComputedCall(
784
"JJ",
785
"",
786
comp(),
787
node->getSymbol()->castToMethodSymbol()->getMethod()->signatureChars(),
788
signatureLength);
789
TR::ResolvedMethodSymbol * owningMethodSymbol = node->getSymbolReference()->getOwningMethodSymbol(comp());
790
TR_ResolvedMethod * dummyMethod = fej9->createResolvedMethodWithSignature(comp()->trMemory(),dummyInvoke, NULL, signature, signatureLength, owningMethodSymbol->getResolvedMethod());
791
TR::SymbolReference * methodSymRef = comp()->getSymRefTab()->findOrCreateMethodSymbol(owningMethodSymbol->getResolvedMethodIndex(), -1, dummyMethod, TR::MethodSymbol::ComputedStatic);
792
793
// construct trees to load target method address (which will either be a thunk or compiled method address) from VFT, but for simplicity let's call it a jitted method entry point
794
TR::Node * xconstSizeofJ9Class = comp()->target().is64Bit()
795
? TR::Node::lconst(node, sizeof(J9Class))
796
: TR::Node::iconst(node, sizeof(J9Class));
797
798
TR::ILOpCodes subOp = comp()->target().is64Bit() ? TR::lsub : TR::isub;
799
TR::ILOpCodes axadd = comp()->target().is64Bit() ? TR::aladd : TR::aiadd;
800
TR::Node* jitVFTOffset = TR::Node::create(subOp, 2, xconstSizeofJ9Class, TR::Node::createLoad(node, vtableOffsetTempSlotSymRef));
801
TR::SymbolReference * vftSymRef = comp()->getSymRefTab()->findOrCreateVftSymbolRef();
802
TR::Node * vftNode = TR::Node::createWithSymRef(node, TR::aloadi, 1, TR::Node::createLoad(node, receiverSymRef), vftSymRef);
803
TR::Node * jitVFTSlotPtr = TR::Node::create(axadd, 2, vftNode, jitVFTOffset);
804
TR::SymbolReference *tSymRef = comp()->getSymRefTab()->findOrCreateGenericIntShadowSymbolReference(0);
805
tSymRef->getSymbol()->setNotCollected();
806
TR::ILOpCodes loadOp = comp()->target().is64Bit() ? TR::lloadi : TR::iloadi;
807
// arg0 ---> jitted method address (in JIT vtable)
808
TR::Node * jittedMethodEntryPoint = TR::Node::createWithSymRef(loadOp, 1, 1, jitVFTSlotPtr, tSymRef);
809
810
// arg1 ---> vtable slot index (jitVFTOffset)
811
812
// 2 additional args prepended (address in vtable entry and vtable slot index), and last arg (MemberName object) removed, so net 1 extra child
813
uint32_t numChildren = node->getNumChildren() + 1;
814
TR::Node * dispatchVirtualCallNode = TR::Node::createWithSymRef(node, node->getSymbol()->castToMethodSymbol()->getMethod()->indirectCallOpCode(), numChildren, methodSymRef);
815
816
// set children for the dispatchVirtual call node
817
dispatchVirtualCallNode->setAndIncChild(0, jittedMethodEntryPoint);
818
dispatchVirtualCallNode->setAndIncChild(1, jitVFTOffset);
819
argsList->pop_back(); //remove MemberName object
820
int32_t child_i = 2;
821
for (auto symRefIt = argsList->begin(); symRefIt != argsList->end(); ++symRefIt)
822
{
823
TR::SymbolReference * currentArg = *symRefIt;
824
dispatchVirtualCallNode->setAndIncChild(child_i, TR::Node::createLoad(node, currentArg));
825
child_i++;
826
}
827
828
TR::TreeTop * dispatchVirtualTreeTop = TR::TreeTop::create(comp(), TR::Node::create(node, TR::treetop, 1, dispatchVirtualCallNode));
829
TR::TreeTop * placeholderINLCallTreeTop = TR::TreeTop::create(comp(), TR::Node::create(node, TR::treetop, 1, placeholderINLCallNode));
830
831
TR::Node *passthroughNode = TR::Node::create(node, TR::PassThrough, 1);
832
passthroughNode->setAndIncChild(0, TR::Node::createLoad(node, argsList->front()));
833
TR::SymbolReference *nullSymRef = comp()->getSymRefTab()->findOrCreateNullCheckSymbolRef(comp()->getMethodSymbol());
834
TR::Node* nullChkNode = TR::Node::createWithSymRef(TR::NULLCHK, 1, 1, passthroughNode, nullSymRef);
835
836
node->removeAllChildren();
837
TR::TransformUtil::createDiamondForCall(this, treetop, vtableOffsetIsNotZeroTreeTop, dispatchVirtualTreeTop, placeholderINLCallTreeTop, false, false);
838
TR::TreeTop *virtualNullCheckTreeTop = TR::TreeTop::create(comp(), nullChkNode);
839
dispatchVirtualTreeTop->insertBefore(virtualNullCheckTreeTop);
840
841
// Insert a conditional at the beginning of the virtual call path to
842
// determine the VFT offset for interface methods.
843
TR::Block *virtualNullCheckBlock = virtualNullCheckTreeTop->getEnclosingBlock();
844
TR::CFG *cfg = comp()->getFlowGraph();
845
TR::Block *itableLookupBlock = virtualNullCheckBlock->split(dispatchVirtualTreeTop, cfg, true);
846
TR::Block *virtualDispatchBlock = itableLookupBlock->split(dispatchVirtualTreeTop, cfg, true);
847
848
TR::ILOpCodes andOp = comp()->target().is64Bit() ? TR::land : TR::iand;
849
TR::Node * xconstITableFlagBit = comp()->target().is64Bit()
850
? TR::Node::lconst(node, J9_JNI_MID_INTERFACE)
851
: TR::Node::iconst(node, (int32_t)J9_JNI_MID_INTERFACE);
852
853
TR::ILOpCodes ifxcmpeq = TR::ILOpCode(ifxcmpne).getOpCodeForReverseBranch();
854
// The offset is a VFT offset iff it is not an itable index
855
TR::Node * ifIsVFTOffset = TR::Node::createif(
856
ifxcmpeq,
857
TR::Node::create(
858
node,
859
andOp,
860
2,
861
TR::Node::createLoad(node, vtableOffsetTempSlotSymRef),
862
xconstITableFlagBit),
863
zero->duplicateTree(), // safe because zero is a constant
864
virtualDispatchBlock->getEntry());
865
866
virtualNullCheckBlock->append(TR::TreeTop::create(comp(), ifIsVFTOffset));
867
cfg->addEdge(virtualNullCheckBlock, virtualDispatchBlock);
868
869
// TODO: For linkToInterface() we should instead use
870
// findOrCreateLookupDynamicPublicInterfaceMethodSymbolRef(), which will
871
// throw IllegalAccessError when the dispatched method is non-public.
872
TR::Node *vftOffsetFromITable = TR::Node::createWithSymRef(
873
node,
874
comp()->target().is64Bit() ? TR::lcall : TR::icall,
875
3,
876
comp()->getSymRefTab()->findOrCreateLookupDynamicInterfaceMethodSymbolRef());
877
878
// The first argument to the itable lookup helper is the receiver class.
879
// It's safe to duplicate vftNode here because it is just a load of
880
// <vft-symbol> from a load of a temp, and the temp has been created
881
// specifically to hold the receiver reference - there are no other defs.
882
//
883
// NOTE: This child is actually last because helper arguments are passed in
884
// reverse order.
885
//
886
vftOffsetFromITable->setAndIncChild(2, vftNode->duplicateTree());
887
888
// The next argument to the itable lookup helper is the interface class.
889
const bool vmtargetIsVolatile = false;
890
const bool vmtargetIsPrivate = false; // could be true? It's a hidden field
891
const bool vmtargetIsFinal = true;
892
TR::SymbolReference * vmtargetSymRef =
893
comp()->getSymRefTab()->findOrFabricateShadowSymbol(
894
comp()->getMethodSymbol(),
895
TR::Symbol::Java_lang_invoke_MemberName_vmtarget,
896
TR::Address,
897
fej9->getVMTargetOffset(),
898
vmtargetIsVolatile,
899
vmtargetIsPrivate,
900
vmtargetIsFinal,
901
"java/lang/invoke/MemberName.vmtarget J");
902
903
vmtargetSymRef->getSymbol()->setNotCollected();
904
905
TR::Node * vmTargetNode = TR::Node::createWithSymRef(
906
node, TR::aloadi, 1, TR::Node::createLoad(node, mnSymRef), vmtargetSymRef);
907
908
TR::SymbolReference *cpField =
909
comp()->getSymRefTab()->findOrCreateJ9MethodConstantPoolFieldSymbolRef(
910
offsetof(struct J9Method, constantPool));
911
912
TR::Node *cpAddrIntWithFlags = TR::Node::createWithSymRef(
913
node, loadOp, 1, vmTargetNode, cpField);
914
915
TR::Node *cpAddrMask = comp()->target().is64Bit()
916
? TR::Node::lconst(~(int64_t)J9_STARTPC_STATUS)
917
: TR::Node::iconst(~(int32_t)J9_STARTPC_STATUS);
918
919
TR::Node *cpAddrInt = TR::Node::create(
920
node, andOp, 2, cpAddrIntWithFlags, cpAddrMask);
921
922
TR::ILOpCodes x2a = comp()->target().is64Bit() ? TR::l2a : TR::i2a;
923
TR::Node *cpAddr = TR::Node::create(node, x2a, 1, cpAddrInt);
924
925
TR::Node *ramClassFieldOffset = comp()->target().is64Bit()
926
? TR::Node::lconst(offsetof (struct J9ConstantPool, ramClass))
927
: TR::Node::iconst(offsetof (struct J9ConstantPool, ramClass));
928
929
TR::Node *ramClassFieldAddr = TR::Node::create(
930
node, axadd, 2, cpAddr, ramClassFieldOffset);
931
932
TR::Node *interfaceClassInt = TR::Node::createWithSymRef(
933
node, loadOp, 1, ramClassFieldAddr, tSymRef);
934
935
TR::Node *interfaceClass = TR::Node::create(node, x2a, 1, interfaceClassInt);
936
vftOffsetFromITable->setAndIncChild(1, interfaceClass);
937
938
// The final argument to the itable lookup helper is the itable index.
939
// NOTE: This child is actually first because helper arguments are passed in
940
// reverse order.
941
TR::Node *xconstClearITableFlagMask = comp()->target().is64Bit()
942
? TR::Node::lconst(node, ~(int64_t)J9_JNI_MID_INTERFACE)
943
: TR::Node::iconst(node, ~(int32_t)J9_JNI_MID_INTERFACE);
944
945
// Duplicate xconstITableFlagBit to prevent commoning between blocks. The
946
// duplication is safe because it's a constant.
947
xconstITableFlagBit = xconstITableFlagBit->duplicateTree();
948
TR::Node *itableIndex = TR::Node::create(
949
andOp,
950
2,
951
TR::Node::createLoad(node, vtableOffsetTempSlotSymRef),
952
xconstClearITableFlagMask);
953
954
vftOffsetFromITable->setAndIncChild(0, itableIndex);
955
956
itableLookupBlock->append(
957
TR::TreeTop::create(
958
comp(),
959
TR::Node::create(node, TR::treetop, 1, vftOffsetFromITable)));
960
961
itableLookupBlock->append(
962
TR::TreeTop::create(
963
comp(),
964
TR::Node::createStore(
965
node, vtableOffsetTempSlotSymRef, vftOffsetFromITable)));
966
967
// -------- path if vmIndex == 0 --------
968
// now let's work with just the placeholder INL call as the main node, as if this is a linkToStatic/Special call. the original treetop was removed.
969
treetop = placeholderINLCallTreeTop;
970
node = treetop->getNode()->getFirstChild();
971
972
// It's safe to duplicate vmTargetNode because it's just a load of vmtarget
973
// from a load of a temp, and the temp has been created specifically to hold
974
// the MemberName reference - there are no other defs
975
vmTargetNode = vmTargetNode->duplicateTree();
976
977
processVMInternalNativeFunction(treetop, node, vmTargetNode, argsList, duplicatedINLCallNode);
978
}
979
#endif // J9VM_OPT_OPENJDK_METHODHANDLE
980
981
bool J9::RecognizedCallTransformer::isInlineable(TR::TreeTop* treetop)
982
{
983
auto node = treetop->getNode()->getFirstChild();
984
TR::RecognizedMethod rm =
985
node->getSymbol()->castToMethodSymbol()->getMandatoryRecognizedMethod();
986
987
bool isILGenPass = !getLastRun();
988
if (isILGenPass)
989
{
990
switch(rm)
991
{
992
case TR::sun_misc_Unsafe_getAndAddInt:
993
return !comp()->getOption(TR_DisableUnsafe) && !comp()->compileRelocatableCode() && !TR::Compiler->om.canGenerateArraylets() &&
994
cg()->supportsNonHelper(TR::SymbolReferenceTable::atomicFetchAndAddSymbol);
995
case TR::sun_misc_Unsafe_getAndSetInt:
996
return !comp()->getOption(TR_DisableUnsafe) && !comp()->compileRelocatableCode() && !TR::Compiler->om.canGenerateArraylets() &&
997
cg()->supportsNonHelper(TR::SymbolReferenceTable::atomicSwapSymbol);
998
case TR::sun_misc_Unsafe_getAndAddLong:
999
return !comp()->getOption(TR_DisableUnsafe) && !comp()->compileRelocatableCode() && !TR::Compiler->om.canGenerateArraylets() && comp()->target().is64Bit() &&
1000
cg()->supportsNonHelper(TR::SymbolReferenceTable::atomicFetchAndAddSymbol);
1001
case TR::sun_misc_Unsafe_getAndSetLong:
1002
return !comp()->getOption(TR_DisableUnsafe) && !comp()->compileRelocatableCode() && !TR::Compiler->om.canGenerateArraylets() && comp()->target().is64Bit() &&
1003
cg()->supportsNonHelper(TR::SymbolReferenceTable::atomicSwapSymbol);
1004
case TR::java_lang_Class_isAssignableFrom:
1005
return cg()->supportsInliningOfIsAssignableFrom();
1006
case TR::java_lang_Integer_rotateLeft:
1007
case TR::java_lang_Integer_rotateRight:
1008
return comp()->target().cpu.getSupportsHardware32bitRotate();
1009
case TR::java_lang_Long_rotateLeft:
1010
case TR::java_lang_Long_rotateRight:
1011
return comp()->target().cpu.getSupportsHardware64bitRotate();
1012
case TR::java_lang_Math_abs_I:
1013
case TR::java_lang_Math_abs_L:
1014
return cg()->supportsIntAbs();
1015
case TR::java_lang_Math_abs_F:
1016
case TR::java_lang_Math_abs_D:
1017
return cg()->supportsFPAbs();
1018
case TR::java_lang_Math_max_I:
1019
case TR::java_lang_Math_min_I:
1020
case TR::java_lang_Math_max_L:
1021
case TR::java_lang_Math_min_L:
1022
return !comp()->getOption(TR_DisableMaxMinOptimization);
1023
case TR::java_lang_StringUTF16_toBytes:
1024
return !comp()->compileRelocatableCode();
1025
case TR::java_lang_StrictMath_sqrt:
1026
case TR::java_lang_Math_sqrt:
1027
return comp()->target().cpu.getSupportsHardwareSQRT();
1028
case TR::java_lang_Short_reverseBytes:
1029
case TR::java_lang_Integer_reverseBytes:
1030
case TR::java_lang_Long_reverseBytes:
1031
return comp()->cg()->supportsByteswap();
1032
case TR::java_lang_StringCoding_encodeASCII:
1033
case TR::java_lang_String_encodeASCII:
1034
return comp()->cg()->getSupportsInlineEncodeASCII();
1035
default:
1036
return false;
1037
}
1038
}
1039
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
1040
else
1041
{
1042
// Post-inlining pass
1043
switch (rm)
1044
{
1045
case TR::java_lang_invoke_MethodHandle_invokeBasic:
1046
if (_processedINLCalls->get(node->getGlobalIndex()))
1047
return false;
1048
else
1049
return true;
1050
case TR::java_lang_invoke_MethodHandle_linkToStatic:
1051
case TR::java_lang_invoke_MethodHandle_linkToSpecial:
1052
// linkToStatic calls are also used for unresolved invokedynamic/invokehandle, which we can not
1053
// bypass as we may push null appendix object that we can not check at compile time
1054
if (_processedINLCalls->get(node->getGlobalIndex()) || node->getSymbolReference()->getSymbol()->isDummyResolvedMethod())
1055
return false;
1056
else
1057
return true;
1058
case TR::java_lang_invoke_MethodHandle_linkToVirtual:
1059
if (_processedINLCalls->get(node->getGlobalIndex()))
1060
return false;
1061
else
1062
return true;
1063
default:
1064
return false;
1065
}
1066
}
1067
#else
1068
return false;
1069
#endif
1070
}
1071
1072
void J9::RecognizedCallTransformer::transform(TR::TreeTop* treetop)
1073
{
1074
auto node = treetop->getNode()->getFirstChild();
1075
TR::RecognizedMethod rm =
1076
node->getSymbol()->castToMethodSymbol()->getMandatoryRecognizedMethod();
1077
1078
bool isILGenPass = !getLastRun();
1079
if (isILGenPass)
1080
{
1081
switch(rm)
1082
{
1083
case TR::sun_misc_Unsafe_getAndAddInt:
1084
case TR::sun_misc_Unsafe_getAndAddLong:
1085
processUnsafeAtomicCall(treetop, TR::SymbolReferenceTable::atomicFetchAndAddSymbol);
1086
break;
1087
case TR::sun_misc_Unsafe_getAndSetInt:
1088
case TR::sun_misc_Unsafe_getAndSetLong:
1089
processUnsafeAtomicCall(treetop, TR::SymbolReferenceTable::atomicSwapSymbol);
1090
break;
1091
case TR::java_lang_Class_isAssignableFrom:
1092
process_java_lang_Class_IsAssignableFrom(treetop, node);
1093
break;
1094
case TR::java_lang_Integer_rotateLeft:
1095
processIntrinsicFunction(treetop, node, TR::irol);
1096
break;
1097
case TR::java_lang_Integer_rotateRight:
1098
{
1099
// rotateRight(x, distance) = rotateLeft(x, -distance)
1100
TR::Node *distance = TR::Node::create(node, TR::ineg, 1);
1101
distance->setChild(0, node->getSecondChild());
1102
node->setAndIncChild(1, distance);
1103
1104
processIntrinsicFunction(treetop, node, TR::irol);
1105
1106
break;
1107
}
1108
case TR::java_lang_Long_rotateLeft:
1109
processIntrinsicFunction(treetop, node, TR::lrol);
1110
break;
1111
case TR::java_lang_Long_rotateRight:
1112
{
1113
// rotateRight(x, distance) = rotateLeft(x, -distance)
1114
TR::Node *distance = TR::Node::create(node, TR::ineg, 1);
1115
distance->setChild(0, node->getSecondChild());
1116
node->setAndIncChild(1, distance);
1117
1118
processIntrinsicFunction(treetop, node, TR::lrol);
1119
1120
break;
1121
}
1122
case TR::java_lang_Math_abs_I:
1123
processIntrinsicFunction(treetop, node, TR::iabs);
1124
break;
1125
case TR::java_lang_Math_abs_L:
1126
processIntrinsicFunction(treetop, node, TR::labs);
1127
break;
1128
case TR::java_lang_Math_abs_D:
1129
processIntrinsicFunction(treetop, node, TR::dabs);
1130
break;
1131
case TR::java_lang_Math_abs_F:
1132
processIntrinsicFunction(treetop, node, TR::fabs);
1133
break;
1134
case TR::java_lang_Math_max_I:
1135
processIntrinsicFunction(treetop, node, TR::imax);
1136
break;
1137
case TR::java_lang_Math_min_I:
1138
processIntrinsicFunction(treetop, node, TR::imin);
1139
break;
1140
case TR::java_lang_Math_max_L:
1141
processIntrinsicFunction(treetop, node, TR::lmax);
1142
break;
1143
case TR::java_lang_Math_min_L:
1144
processIntrinsicFunction(treetop, node, TR::lmin);
1145
break;
1146
case TR::java_lang_StringUTF16_toBytes:
1147
process_java_lang_StringUTF16_toBytes(treetop, node);
1148
break;
1149
case TR::java_lang_StringCoding_encodeASCII:
1150
case TR::java_lang_String_encodeASCII:
1151
process_java_lang_StringCoding_encodeASCII(treetop, node);
1152
break;
1153
case TR::java_lang_StrictMath_sqrt:
1154
case TR::java_lang_Math_sqrt:
1155
process_java_lang_StrictMath_and_Math_sqrt(treetop, node);
1156
break;
1157
case TR::java_lang_Short_reverseBytes:
1158
processConvertingUnaryIntrinsicFunction(treetop, node, TR::i2s, TR::sbyteswap, TR::s2i);
1159
break;
1160
case TR::java_lang_Integer_reverseBytes:
1161
processIntrinsicFunction(treetop, node, TR::ibyteswap);
1162
break;
1163
case TR::java_lang_Long_reverseBytes:
1164
processIntrinsicFunction(treetop, node, TR::lbyteswap);
1165
break;
1166
default:
1167
break;
1168
}
1169
}
1170
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
1171
else
1172
{
1173
// Post-inlining pass
1174
switch (rm)
1175
{
1176
case TR::java_lang_invoke_MethodHandle_invokeBasic:
1177
process_java_lang_invoke_MethodHandle_invokeBasic(treetop, node);
1178
break;
1179
case TR::java_lang_invoke_MethodHandle_linkToStatic:
1180
case TR::java_lang_invoke_MethodHandle_linkToSpecial:
1181
process_java_lang_invoke_MethodHandle_linkToStaticSpecial(treetop, node);
1182
break;
1183
case TR::java_lang_invoke_MethodHandle_linkToVirtual:
1184
process_java_lang_invoke_MethodHandle_linkToVirtual(treetop, node);
1185
break;
1186
default:
1187
break;
1188
}
1189
}
1190
#endif
1191
}
1192
1193