Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/aarch64/codegen/CallSnippet.cpp
6004 views
1
/*******************************************************************************
2
* Copyright (c) 2019, 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 "codegen/CallSnippet.hpp"
24
#include "codegen/ARM64AOTRelocation.hpp"
25
#include "codegen/ARM64Instruction.hpp"
26
#include "codegen/CodeGenerator.hpp"
27
#include "codegen/InstOpCode.hpp"
28
#include "codegen/Linkage.hpp"
29
#include "codegen/Linkage_inlines.hpp"
30
#include "codegen/Machine.hpp"
31
#include "codegen/Register.hpp"
32
#include "env/CompilerEnv.hpp"
33
#include "env/J2IThunk.hpp"
34
#include "il/LabelSymbol.hpp"
35
#include "il/Node.hpp"
36
#include "il/Node_inlines.hpp"
37
38
static uint8_t *storeArgumentItem(TR::InstOpCode::Mnemonic op, uint8_t *buffer, TR::RealRegister *reg, int32_t offset, TR::CodeGenerator *cg)
39
{
40
TR::RealRegister *stackPtr = cg->getStackPointerRegister();
41
TR::InstOpCode opCode(op);
42
uint32_t enc = (uint32_t)opCode.getOpCodeBinaryEncoding();
43
TR_ASSERT((enc & 0x3b200000) == 0x39000000, "Instruction not supported in storeArgumentItem()");
44
45
uint32_t size = (enc >> 30) & 3; /* b=0, h=1, w=2, x=3 */
46
uint32_t shifted = offset >> size;
47
uint32_t *wcursor = (uint32_t *)buffer;
48
49
opCode.copyBinaryToBuffer(buffer);
50
reg->setRegisterFieldRT(wcursor);
51
stackPtr->setRegisterFieldRN(wcursor);
52
*wcursor |= (shifted & 0xfff) << 10; /* imm12 */
53
54
return buffer+4;
55
}
56
57
static uint8_t *flushArgumentsToStack(uint8_t *buffer, TR::Node *callNode, int32_t argSize, TR::CodeGenerator *cg)
58
{
59
uint32_t intArgNum=0, floatArgNum=0, offset;
60
TR::Machine *machine = cg->machine();
61
TR::Linkage* linkage = cg->getLinkage(callNode->getSymbol()->castToMethodSymbol()->getLinkageConvention());
62
const TR::ARM64LinkageProperties &linkageProperties = linkage->getProperties();
63
int32_t argStart = callNode->getFirstArgumentIndex();
64
65
if (linkageProperties.getRightToLeft())
66
offset = linkage->getOffsetToFirstParm();
67
else
68
offset = argSize+linkage->getOffsetToFirstParm();
69
70
for (int32_t i=argStart; i<callNode->getNumChildren();i++)
71
{
72
TR::Node *child = callNode->getChild(i);
73
switch (child->getDataType())
74
{
75
case TR::Int8:
76
case TR::Int16:
77
case TR::Int32:
78
if (!linkageProperties.getRightToLeft())
79
offset -= TR::Compiler->om.sizeofReferenceAddress();
80
if (intArgNum < linkageProperties.getNumIntArgRegs())
81
{
82
buffer = storeArgumentItem(TR::InstOpCode::strimmw, buffer, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), offset, cg);
83
}
84
intArgNum++;
85
if (linkageProperties.getRightToLeft())
86
offset += TR::Compiler->om.sizeofReferenceAddress();
87
break;
88
case TR::Address:
89
if (!linkageProperties.getRightToLeft())
90
offset -= TR::Compiler->om.sizeofReferenceAddress();
91
if (intArgNum < linkageProperties.getNumIntArgRegs())
92
{
93
buffer = storeArgumentItem(TR::InstOpCode::strimmx, buffer, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), offset, cg);
94
}
95
intArgNum++;
96
if (linkageProperties.getRightToLeft())
97
offset += TR::Compiler->om.sizeofReferenceAddress();
98
break;
99
case TR::Int64:
100
if (!linkageProperties.getRightToLeft())
101
offset -= 2*TR::Compiler->om.sizeofReferenceAddress();
102
if (intArgNum < linkageProperties.getNumIntArgRegs())
103
{
104
buffer = storeArgumentItem(TR::InstOpCode::strimmx, buffer, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), offset, cg);
105
}
106
intArgNum++;
107
if (linkageProperties.getRightToLeft())
108
offset += 2*TR::Compiler->om.sizeofReferenceAddress();
109
break;
110
case TR::Float:
111
if (!linkageProperties.getRightToLeft())
112
offset -= TR::Compiler->om.sizeofReferenceAddress();
113
if (floatArgNum < linkageProperties.getNumFloatArgRegs())
114
{
115
buffer = storeArgumentItem(TR::InstOpCode::vstrimms, buffer, machine->getRealRegister(linkageProperties.getFloatArgumentRegister(floatArgNum)), offset, cg);
116
}
117
floatArgNum++;
118
if (linkageProperties.getRightToLeft())
119
offset += TR::Compiler->om.sizeofReferenceAddress();
120
break;
121
case TR::Double:
122
if (!linkageProperties.getRightToLeft())
123
offset -= 2*TR::Compiler->om.sizeofReferenceAddress();
124
if (floatArgNum < linkageProperties.getNumFloatArgRegs())
125
{
126
buffer = storeArgumentItem(TR::InstOpCode::vstrimmd, buffer, machine->getRealRegister(linkageProperties.getFloatArgumentRegister(floatArgNum)), offset, cg);
127
}
128
floatArgNum++;
129
if (linkageProperties.getRightToLeft())
130
offset += 2*TR::Compiler->om.sizeofReferenceAddress();
131
break;
132
}
133
}
134
135
return buffer;
136
}
137
138
static int32_t instructionCountForArguments(TR::Node *callNode, TR::CodeGenerator *cg)
139
{
140
uint32_t intArgNum=0, floatArgNum=0, count=0;
141
const TR::ARM64LinkageProperties &linkage = cg->getLinkage(callNode->getSymbol()->castToMethodSymbol()->getLinkageConvention())->getProperties();
142
int32_t argStart = callNode->getFirstArgumentIndex();
143
144
for (int32_t i = argStart; i < callNode->getNumChildren(); i++)
145
{
146
TR::Node *child = callNode->getChild(i);
147
switch (child->getDataType())
148
{
149
case TR::Int8:
150
case TR::Int16:
151
case TR::Int32:
152
case TR::Int64:
153
case TR::Address:
154
if (intArgNum < linkage.getNumIntArgRegs())
155
{
156
count++;
157
}
158
intArgNum++;
159
break;
160
case TR::Float:
161
case TR::Double:
162
if (floatArgNum < linkage.getNumFloatArgRegs())
163
{
164
count++;
165
}
166
floatArgNum++;
167
break;
168
}
169
}
170
171
return count;
172
}
173
174
static int32_t
175
getBLDistance(uint8_t *cursor)
176
{
177
// branch distance of BL instruction
178
int32_t distance;
179
distance = *((int32_t *)cursor) & 0x03ffffff; // imm26
180
distance = (distance << 6) >> 4; // sign extend and add two 0 bits
181
return distance;
182
}
183
184
TR_RuntimeHelper TR::ARM64CallSnippet::getHelper()
185
{
186
TR::Compilation * comp = cg()->comp();
187
TR::Node *callNode = getNode();
188
TR::SymbolReference *methodSymRef = callNode->getSymbolReference();
189
TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();
190
TR::SymbolReference *glueRef = NULL;
191
bool isJitInduceOSRCall = false;
192
if (methodSymbol->isHelper() &&
193
methodSymRef->isOSRInductionHelper())
194
{
195
isJitInduceOSRCall = true;
196
}
197
198
if (methodSymRef->isUnresolved() || comp->compileRelocatableCode())
199
{
200
if (methodSymbol->isSpecial())
201
return TR_ARM64interpreterUnresolvedSpecialGlue;
202
if (methodSymbol->isStatic())
203
return TR_ARM64interpreterUnresolvedStaticGlue;
204
return TR_ARM64interpreterUnresolvedDirectVirtualGlue;
205
}
206
207
if (methodSymbol->isVMInternalNative() || methodSymbol->isJITInternalNative())
208
return TR_ARM64nativeStaticHelper;
209
210
if (isJitInduceOSRCall)
211
return (TR_RuntimeHelper) methodSymRef->getReferenceNumber();
212
213
bool synchronised = methodSymbol->isSynchronised();
214
215
TR::DataType dataType = callNode->getDataType();
216
switch (dataType)
217
{
218
case TR::NoType:
219
return synchronised ? TR_ARM64interpreterSyncVoidStaticGlue : TR_ARM64interpreterVoidStaticGlue;
220
case TR::Int32:
221
return synchronised ? TR_ARM64interpreterSyncIntStaticGlue : TR_ARM64interpreterIntStaticGlue;
222
case TR::Int64:
223
case TR::Address:
224
return synchronised ? TR_ARM64interpreterSyncLongStaticGlue : TR_ARM64interpreterLongStaticGlue;
225
case TR::Float:
226
return synchronised ? TR_ARM64interpreterSyncFloatStaticGlue : TR_ARM64interpreterFloatStaticGlue;
227
case TR::Double:
228
return synchronised ? TR_ARM64interpreterSyncDoubleStaticGlue : TR_ARM64interpreterDoubleStaticGlue;
229
default:
230
TR_ASSERT_FATAL(false, "Bad return data type '%s' for a call node.\n",
231
cg()->getDebug()->getName(dataType));
232
return (TR_RuntimeHelper)0;
233
}
234
}
235
236
uint8_t *TR::ARM64CallSnippet::emitSnippetBody()
237
{
238
uint8_t *cursor = cg()->getBinaryBufferCursor();
239
TR::Node *callNode = getNode();
240
TR::SymbolReference *methodSymRef = callNode->getSymbolReference();
241
TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();
242
TR::SymbolReference *glueRef;
243
TR::Compilation *comp = cg()->comp();
244
void *trmpln = NULL;
245
246
getSnippetLabel()->setCodeLocation(cursor);
247
248
// Flush in-register arguments back to the stack for interpreter
249
cursor = flushArgumentsToStack(cursor, callNode, getSizeOfArguments(), cg());
250
251
glueRef = cg()->symRefTab()->findOrCreateRuntimeHelper(getHelper());
252
253
// 'b glueRef' for jitInduceOSRAtCurrentPC, 'bl glueRef' otherwise
254
// we use "b" for induceOSR because we want the helper to think that it's been called from the mainline code and not from the snippet.
255
*(int32_t *)cursor = cg()->encodeHelperBranchAndLink(glueRef, cursor, callNode, glueRef->isOSRInductionHelper());
256
cursor += 4;
257
258
// Store the code cache RA
259
*(intptr_t *)cursor = (intptr_t)getCallRA();
260
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(
261
cursor,
262
NULL,
263
TR_AbsoluteMethodAddress, cg()),
264
__FILE__, __LINE__, getNode());
265
cursor += 8;
266
267
//induceOSRAtCurrentPC is implemented in the VM, and it knows, by looking at the current PC, what method it needs to
268
//continue execution in interpreted mode. Therefore, it doesn't need the method pointer.
269
if (!glueRef->isOSRInductionHelper())
270
{
271
// Store the method pointer: it is NULL for unresolved
272
if (methodSymRef->isUnresolved() || comp->compileRelocatableCode())
273
{
274
*(intptr_t *)cursor = 0;
275
if (comp->getOption(TR_EnableHCR))
276
{
277
cg()->jitAddPicToPatchOnClassRedefinition((void*)-1, (void *)cursor, true);
278
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation((uint8_t *)cursor, NULL,(uint8_t *)needsFullSizeRuntimeAssumption,
279
TR_HCR, cg()),
280
__FILE__, __LINE__, getNode());
281
}
282
}
283
else
284
{
285
*(intptr_t *)cursor = (intptr_t)methodSymbol->getMethodAddress();
286
if (comp->getOption(TR_EnableHCR))
287
{
288
cg()->jitAddPicToPatchOnClassRedefinition((void *)methodSymbol->getMethodAddress(), (void *)cursor);
289
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, (uint8_t *)methodSymRef,
290
getNode() ? (uint8_t *)getNode()->getInlinedSiteIndex() : (uint8_t *)-1,
291
TR_MethodObject, cg()),
292
__FILE__, __LINE__, callNode);
293
}
294
}
295
}
296
cursor += 8;
297
298
// Lock word initialized to 0
299
*(int32_t *)cursor = 0;
300
301
return cursor+4;
302
}
303
304
static void
305
printArgumentFlush(TR_Debug *debug, TR::FILE *pOutFile, uint8_t *cursor, const char *mnemonic, uint32_t offset, TR::Register *reg, TR::Register *stackReg)
306
{
307
debug->printPrefix(pOutFile, NULL, cursor, 4);
308
trfprintf(pOutFile, "%s \t", mnemonic);
309
debug->print(pOutFile, reg, TR_WordReg);
310
trfprintf(pOutFile, ", [");
311
debug->print(pOutFile, stackReg, TR_WordReg);
312
trfprintf(pOutFile, ", %d]", offset);
313
}
314
315
uint8_t *
316
TR_Debug::printARM64ArgumentsFlush(TR::FILE *pOutFile, TR::Node *callNode, uint8_t *cursor, int32_t argSize)
317
{
318
uint32_t intArgNum=0, floatArgNum=0, offset;
319
TR::Machine *machine = _cg->machine();
320
TR::Linkage* linkage = _cg->getLinkage(callNode->getSymbol()->castToMethodSymbol()->getLinkageConvention());
321
const TR::ARM64LinkageProperties &linkageProperties = linkage->getProperties();
322
int32_t argStart = callNode->getFirstArgumentIndex();
323
TR::RealRegister *stackPtr = _cg->getStackPointerRegister();
324
325
if (linkageProperties.getRightToLeft())
326
offset = linkage->getOffsetToFirstParm();
327
else
328
offset = argSize+linkage->getOffsetToFirstParm();
329
330
for (int32_t i=argStart; i<callNode->getNumChildren();i++)
331
{
332
TR::Node *child = callNode->getChild(i);
333
switch (child->getDataType())
334
{
335
case TR::Int8:
336
case TR::Int16:
337
case TR::Int32:
338
if (!linkageProperties.getRightToLeft())
339
offset -= TR::Compiler->om.sizeofReferenceAddress();
340
if (intArgNum < linkageProperties.getNumIntArgRegs())
341
{
342
printArgumentFlush(this, pOutFile, cursor, "strimmw", offset, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), stackPtr);
343
cursor += 4;
344
}
345
intArgNum++;
346
if (linkageProperties.getRightToLeft())
347
offset += TR::Compiler->om.sizeofReferenceAddress();
348
break;
349
case TR::Address:
350
if (!linkageProperties.getRightToLeft())
351
offset -= TR::Compiler->om.sizeofReferenceAddress();
352
if (intArgNum < linkageProperties.getNumIntArgRegs())
353
{
354
printArgumentFlush(this, pOutFile, cursor, "strimmx", offset, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), stackPtr);
355
cursor += 4;
356
}
357
intArgNum++;
358
if (linkageProperties.getRightToLeft())
359
offset += TR::Compiler->om.sizeofReferenceAddress();
360
break;
361
case TR::Int64:
362
if (!linkageProperties.getRightToLeft())
363
offset -= 2*TR::Compiler->om.sizeofReferenceAddress();
364
if (intArgNum < linkageProperties.getNumIntArgRegs())
365
{
366
printArgumentFlush(this, pOutFile, cursor, "strimmx", offset, machine->getRealRegister(linkageProperties.getIntegerArgumentRegister(intArgNum)), stackPtr);
367
cursor += 4;
368
}
369
intArgNum++;
370
if (linkageProperties.getRightToLeft())
371
offset += 2*TR::Compiler->om.sizeofReferenceAddress();
372
break;
373
case TR::Float:
374
if (!linkageProperties.getRightToLeft())
375
offset -= TR::Compiler->om.sizeofReferenceAddress();
376
if (floatArgNum < linkageProperties.getNumFloatArgRegs())
377
{
378
printArgumentFlush(this, pOutFile, cursor, "vstrimms", offset, machine->getRealRegister(linkageProperties.getFloatArgumentRegister(floatArgNum)), stackPtr);
379
cursor += 4;
380
}
381
floatArgNum++;
382
if (linkageProperties.getRightToLeft())
383
offset += TR::Compiler->om.sizeofReferenceAddress();
384
break;
385
case TR::Double:
386
if (!linkageProperties.getRightToLeft())
387
offset -= 2*TR::Compiler->om.sizeofReferenceAddress();
388
if (floatArgNum < linkageProperties.getNumFloatArgRegs())
389
{
390
printArgumentFlush(this, pOutFile, cursor, "vstrimmd", offset, machine->getRealRegister(linkageProperties.getFloatArgumentRegister(floatArgNum)), stackPtr);
391
cursor += 4;
392
}
393
floatArgNum++;
394
if (linkageProperties.getRightToLeft())
395
offset += 2*TR::Compiler->om.sizeofReferenceAddress();
396
break;
397
398
default:
399
TR_ASSERT_FATAL(false, "Unknown argument type %d", child->getDataType());
400
break;
401
}
402
}
403
return cursor;
404
}
405
406
void
407
TR_Debug::print(TR::FILE *pOutFile, TR::ARM64CallSnippet *snippet)
408
{
409
TR::Node *callNode = snippet->getNode();
410
TR::SymbolReference *glueRef = _cg->getSymRef(snippet->getHelper());
411
TR::SymbolReference *methodSymRef = callNode->getSymbolReference();
412
TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();
413
414
uint8_t *bufferPos = snippet->getSnippetLabel()->getCodeLocation();
415
printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, getName(snippet), getName(methodSymRef));
416
417
bufferPos = printARM64ArgumentsFlush(pOutFile, callNode, bufferPos, snippet->getSizeOfArguments());
418
419
char *info = "";
420
intptr_t target = reinterpret_cast<intptr_t>(glueRef->getMethodAddress());
421
int32_t distance;
422
if (isBranchToTrampoline(glueRef, bufferPos, distance))
423
{
424
target = static_cast<intptr_t>(distance) + reinterpret_cast<intptr_t>(bufferPos);
425
info = " Through trampoline";
426
TR_ASSERT_FATAL(constantIsSignedImm28(distance), "Trampoline too far away.");
427
}
428
429
printPrefix(pOutFile, NULL, bufferPos, 4);
430
trfprintf(pOutFile, "%s \t" POINTER_PRINTF_FORMAT "\t\t; %s%s", (glueRef->isOSRInductionHelper() ? "b" : "bl"), target, getName(glueRef), info);
431
bufferPos += 4;
432
433
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
434
trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Code cache return address", snippet->getCallRA());
435
bufferPos += sizeof(intptr_t);
436
437
if (!glueRef->isOSRInductionHelper())
438
{
439
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
440
trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Method Pointer", *(reinterpret_cast<uintptr_t *>(bufferPos)));
441
bufferPos += sizeof(intptr_t);
442
}
443
444
printPrefix(pOutFile, NULL, bufferPos, 4);
445
trfprintf(pOutFile, ".word \t0x%08x\t\t; Lock Word For Compilation", *(reinterpret_cast<int32_t *>(bufferPos)));
446
}
447
448
uint32_t TR::ARM64CallSnippet::getLength(int32_t estimatedSnippetStart)
449
{
450
return (instructionCountForArguments(getNode(), cg()) + 6) * 4;
451
}
452
453
uint8_t *TR::ARM64VirtualSnippet::emitSnippetBody()
454
{
455
return NULL;
456
}
457
458
uint32_t TR::ARM64VirtualSnippet::getLength(int32_t estimatedSnippetStart)
459
{
460
return 0;
461
}
462
463
uint8_t *TR::ARM64UnresolvedCallSnippet::emitSnippetBody()
464
{
465
uint8_t *cursor = TR::ARM64CallSnippet::emitSnippetBody();
466
467
TR::SymbolReference *methodSymRef = getNode()->getSymbolReference();
468
TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();
469
intptr_t helperLookupOffset;
470
471
TR::Compilation* comp = cg()->comp();
472
473
// CP
474
*(intptr_t *)cursor = (intptr_t)methodSymRef->getOwningMethod(comp)->constantPool();
475
476
if (comp->compileRelocatableCode() && comp->getOption(TR_TraceRelocatableDataDetailsCG))
477
{
478
traceMsg(comp, "<relocatableDataTrampolinesCG>\n");
479
traceMsg(comp, "%s\n", comp->signature());
480
traceMsg(comp, "%-8s", "cpIndex");
481
traceMsg(comp, "cp\n");
482
traceMsg(comp, "%-8x", methodSymRef->getCPIndexForVM());
483
traceMsg(comp, "%x\n", methodSymRef->getOwningMethod(comp)->constantPool());
484
traceMsg(comp, "</relocatableDataTrampolinesCG>\n");
485
}
486
487
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(
488
cursor,
489
*(uint8_t **)cursor,
490
getNode() ? (uint8_t *)getNode()->getInlinedSiteIndex() : (uint8_t *)-1,
491
TR_Trampolines, cg()),
492
__FILE__, __LINE__, getNode());
493
cursor += 8;
494
495
switch (getNode()->getDataType())
496
{
497
case TR::NoType:
498
helperLookupOffset = 0;
499
break;
500
case TR::Int32:
501
helperLookupOffset = 8;
502
break;
503
case TR::Int64:
504
case TR::Address:
505
helperLookupOffset = 16;
506
break;
507
case TR::Float:
508
helperLookupOffset = 24;
509
break;
510
case TR::Double:
511
helperLookupOffset = 32;
512
break;
513
}
514
515
// CP index and helper offset
516
*(intptr_t *)cursor = (helperLookupOffset<<56) | methodSymRef->getCPIndexForVM();
517
518
return cursor + 8;
519
}
520
521
void
522
TR_Debug::print(TR::FILE *pOutFile, TR::ARM64UnresolvedCallSnippet *snippet)
523
{
524
print(pOutFile, (TR::ARM64CallSnippet *) snippet);
525
526
uint8_t *cursor = snippet->getSnippetLabel()->getCodeLocation() + snippet->getLength(0) - (sizeof(intptr_t) * 2);
527
528
TR::SymbolReference *methodSymRef = snippet->getNode()->getSymbolReference();
529
TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();
530
531
intptr_t helperLookupOffset;
532
switch (snippet->getNode()->getDataType())
533
{
534
case TR::NoType:
535
helperLookupOffset = 0;
536
break;
537
case TR::Int32:
538
helperLookupOffset = 8;
539
break;
540
case TR::Int64:
541
case TR::Address:
542
helperLookupOffset = 16;
543
break;
544
case TR::Float:
545
helperLookupOffset = 24;
546
break;
547
case TR::Double:
548
helperLookupOffset = 32;
549
break;
550
}
551
552
printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));
553
trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Pointer To Constant Pool", *(reinterpret_cast<intptr_t *>(cursor)));
554
cursor += sizeof(intptr_t);
555
556
printPrefix(pOutFile, NULL, cursor, 8);
557
trfprintf(pOutFile,
558
".dword \t%016llx\t\t; Offset | Flag | CP Index",
559
(helperLookupOffset << 56) | methodSymRef->getCPIndexForVM());
560
cursor += 8;
561
}
562
563
uint32_t TR::ARM64UnresolvedCallSnippet::getLength(int32_t estimatedSnippetStart)
564
{
565
return TR::ARM64CallSnippet::getLength(estimatedSnippetStart) + 16;
566
}
567
568
uint8_t *TR::ARM64VirtualUnresolvedSnippet::emitSnippetBody()
569
{
570
TR::Compilation* comp = cg()->comp();
571
uint8_t *cursor = cg()->getBinaryBufferCursor();
572
TR::Node *callNode = getNode();
573
TR::SymbolReference *methodSymRef = callNode->getSymbolReference();
574
TR::SymbolReference *glueRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_ARM64virtualUnresolvedHelper);
575
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());
576
void *thunk = fej9->getJ2IThunk(callNode->getSymbolReference()->getSymbol()->castToMethodSymbol()->getMethod(), comp);
577
578
// for alignment of intptr_t data
579
if (((uint64_t)cursor % sizeof(intptr_t)) == 0)
580
{
581
*(int32_t *)cursor = 0xdeadc0de;
582
cursor += sizeof(int32_t);
583
}
584
585
getSnippetLabel()->setCodeLocation(cursor);
586
587
// bl glueRef
588
*(int32_t *)cursor = cg()->encodeHelperBranchAndLink(glueRef, cursor, callNode);
589
cursor += ARM64_INSTRUCTION_LENGTH;
590
TR_ASSERT(((uint64_t)cursor % sizeof(intptr_t)) == 0, "Snippet data is not aligned");
591
592
// Store the code cache RA
593
*(intptr_t *)cursor = (intptr_t)getReturnLabel()->getCodeLocation();
594
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(
595
cursor,
596
NULL,
597
TR_AbsoluteMethodAddress, cg()),
598
__FILE__, __LINE__, callNode);
599
cursor += sizeof(intptr_t);
600
601
// CP
602
intptr_t cpAddr = (intptr_t)methodSymRef->getOwningMethod(comp)->constantPool();
603
*(intptr_t *)cursor = cpAddr;
604
uint8_t *j2iThunkRelocationPoint = cursor;
605
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(
606
cursor,
607
*(uint8_t **)cursor,
608
getNode() ? (uint8_t *)getNode()->getInlinedSiteIndex() : (uint8_t *)-1,
609
TR_Thunks, cg()),
610
__FILE__, __LINE__, getNode());
611
cursor += sizeof(intptr_t);
612
613
// CP index
614
*(intptr_t *)cursor = methodSymRef->getCPIndexForVM();
615
cursor += sizeof(intptr_t);
616
617
// Reserved spot to hold J9Method pointer of the callee
618
// This is used for private nestmate calls
619
// Initial value is 0
620
*(intptr_t *)cursor = 0;
621
cursor += sizeof(intptr_t);
622
623
// J2I thunk address
624
// This is used for private nestmate calls
625
*(intptr_t*)cursor = (intptr_t)thunk;
626
627
auto info =
628
(TR_RelocationRecordInformation *)comp->trMemory()->allocateMemory(
629
sizeof (TR_RelocationRecordInformation),
630
heapAlloc);
631
632
// data1 = constantPool
633
info->data1 = cpAddr;
634
635
// data2 = inlined site index
636
info->data2 = callNode ? callNode->getInlinedSiteIndex() : (uintptr_t)-1;
637
638
// data3 = distance in bytes from Constant Pool Pointer to J2I Thunk
639
info->data3 = (intptr_t)cursor - (intptr_t)j2iThunkRelocationPoint;
640
641
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(
642
j2iThunkRelocationPoint,
643
(uint8_t *)info,
644
NULL,
645
TR_J2IVirtualThunkPointer, cg()),
646
__FILE__, __LINE__, callNode);
647
648
cursor += sizeof(intptr_t);
649
650
// Lock word
651
*(int32_t *)cursor = 0;
652
653
return cursor + sizeof(int32_t);
654
}
655
656
void
657
TR_Debug::print(TR::FILE *pOutFile, TR::ARM64VirtualUnresolvedSnippet * snippet)
658
{
659
TR::SymbolReference *callSymRef = snippet->getNode()->getSymbolReference();
660
uint8_t *cursor = snippet->getSnippetLabel()->getCodeLocation();
661
662
printSnippetLabel(pOutFile, snippet->getSnippetLabel(), cursor, getName(snippet), getName(callSymRef));
663
664
int32_t distance = getBLDistance(cursor);
665
printPrefix(pOutFile, NULL, cursor, ARM64_INSTRUCTION_LENGTH);
666
trfprintf(pOutFile, "bl \t" POINTER_PRINTF_FORMAT "\t\t; %s",
667
(intptr_t)cursor + distance, getRuntimeHelperName(TR_ARM64virtualUnresolvedHelper));
668
cursor += ARM64_INSTRUCTION_LENGTH;
669
670
printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));
671
trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Code cache return address", *(intptr_t *)cursor);
672
cursor += sizeof(intptr_t);
673
674
printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));
675
trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Constant pool address", *(intptr_t *)cursor);
676
cursor += sizeof(intptr_t);
677
678
printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));
679
trfprintf(pOutFile, ".dword \t0x%08x\t\t; cpIndex", *(intptr_t *)cursor);
680
cursor += sizeof(intptr_t);
681
682
printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));
683
trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Private J9Method pointer", *(intptr_t *)cursor);
684
cursor += sizeof(intptr_t);
685
686
printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));
687
trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; J2I thunk address for private", *(intptr_t *)cursor);
688
cursor += sizeof(intptr_t);
689
690
printPrefix(pOutFile, NULL, cursor, sizeof(int32_t));
691
trfprintf(pOutFile, ".word \t0x%08x\t\t; Lock Word For Resolution", *(int32_t *)cursor);
692
}
693
694
uint32_t TR::ARM64VirtualUnresolvedSnippet::getLength(int32_t estimatedSnippetStart)
695
{
696
/*
697
* (1 word for alignment)
698
* 1 instruction
699
* 5 address fields:
700
* - Code cache RA
701
* - CP pointer
702
* - CP index
703
* - Private J9Method pointer
704
* - J2I thunk address
705
* 1 lock word
706
*/
707
return ARM64_INSTRUCTION_LENGTH + sizeof(intptr_t)*5 + sizeof(int32_t)*2;
708
}
709
710
uint8_t *TR::ARM64InterfaceCallSnippet::emitSnippetBody()
711
{
712
TR::Compilation *comp = cg()->comp();
713
uint8_t *cursor = cg()->getBinaryBufferCursor();
714
uint8_t *blAddress;
715
TR::Node *callNode = getNode();
716
TR::SymbolReference *methodSymRef = getNode()->getSymbolReference();
717
TR::SymbolReference *glueRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_ARM64interfaceCallHelper);
718
TR_J9VMBase *fej9 = reinterpret_cast<TR_J9VMBase *>(comp->fe());
719
void* thunk = fej9->getJ2IThunk(callNode->getSymbolReference()->getSymbol()->castToMethodSymbol()->getMethod(), comp);
720
721
// for alignment of intptr_t data
722
if ((reinterpret_cast<uint64_t>(cursor) % sizeof(intptr_t)) == 0)
723
{
724
*reinterpret_cast<int32_t *>(cursor) = 0xdeadc0de;
725
cursor += sizeof(int32_t);
726
}
727
728
getSnippetLabel()->setCodeLocation(cursor);
729
730
// bl glueRef
731
*reinterpret_cast<uint32_t *>(cursor) = cg()->encodeHelperBranchAndLink(glueRef, cursor, callNode);
732
blAddress = cursor;
733
cursor += ARM64_INSTRUCTION_LENGTH;
734
TR_ASSERT_FATAL((reinterpret_cast<uint64_t>(cursor) % sizeof(intptr_t)) == 0, "Snippet data is not aligned");
735
736
// Store the code cache RA
737
*(intptr_t *)cursor = (intptr_t)getReturnLabel()->getCodeLocation();
738
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(
739
cursor,
740
NULL,
741
TR_AbsoluteMethodAddress, cg()),
742
__FILE__, __LINE__, callNode);
743
cursor += sizeof(intptr_t);
744
745
// CP
746
intptr_t cpAddr = reinterpret_cast<intptr_t>(methodSymRef->getOwningMethod(comp)->constantPool());
747
*reinterpret_cast<intptr_t *>(cursor) = cpAddr;
748
uint8_t *j2iThunkRelocationPoint = cursor;
749
cursor += sizeof(intptr_t);
750
751
// CP index
752
*reinterpret_cast<intptr_t *>(cursor) = methodSymRef->getCPIndexForVM();
753
cursor += sizeof(intptr_t);
754
755
// 2 slots for resolved values (interface class and iTable index)
756
*reinterpret_cast<intptr_t *>(cursor) = 0;
757
cursor += sizeof(intptr_t);
758
*reinterpret_cast<intptr_t *>(cursor) = 0;
759
cursor += sizeof(intptr_t);
760
761
_firstClassCacheSlotLabel->setCodeLocation(cursor);
762
_firstBranchAddressCacheSlotLabel->setCodeLocation(cursor + sizeof(intptr_t));
763
_secondClassCacheSlotLabel->setCodeLocation(cursor + 2*sizeof(intptr_t));
764
_secondBranchAddressCacheSlotLabel->setCodeLocation(cursor + 3*sizeof(intptr_t));
765
// Initialize for: two class ptrs, two target addrs
766
// Initialize target addrs with the address of the bl
767
*reinterpret_cast<intptr_t *>(cursor) = -1;
768
*reinterpret_cast<intptr_t *>(cursor + sizeof(intptr_t)) = reinterpret_cast<intptr_t>(blAddress);
769
*reinterpret_cast<intptr_t *>(cursor + 2*sizeof(intptr_t)) = -1;
770
*reinterpret_cast<intptr_t *>(cursor + 3*sizeof(intptr_t)) = reinterpret_cast<intptr_t>(blAddress);
771
772
// Register for relocation of the 1st target address
773
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor + sizeof(intptr_t), NULL, TR_AbsoluteMethodAddress, cg()),
774
__FILE__, __LINE__, callNode);
775
776
// Register for relocation of the 2nd target address
777
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor + 3*sizeof(intptr_t), NULL, TR_AbsoluteMethodAddress, cg()),
778
__FILE__, __LINE__, callNode);
779
780
cursor += 4*sizeof(intptr_t);
781
782
/*
783
* J2I thunk address.
784
* This is used for private nestmate calls.
785
*/
786
*reinterpret_cast<intptr_t*>(cursor) = reinterpret_cast<intptr_t>(thunk);
787
if (comp->compileRelocatableCode())
788
{
789
auto info =
790
(TR_RelocationRecordInformation *)comp->trMemory()->allocateMemory(
791
sizeof(TR_RelocationRecordInformation),
792
heapAlloc);
793
794
// data1 = constantPool
795
info->data1 = cpAddr;
796
797
// data2 = inlined site index
798
info->data2 = callNode ? callNode->getInlinedSiteIndex() : static_cast<uintptr_t>(-1);
799
800
// data3 = distance in bytes from Constant Pool Pointer to J2I Thunk
801
info->data3 = reinterpret_cast<intptr_t>(cursor) - reinterpret_cast<intptr_t>(j2iThunkRelocationPoint);
802
803
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(
804
j2iThunkRelocationPoint,
805
reinterpret_cast<uint8_t *>(info),
806
NULL,
807
TR_J2IVirtualThunkPointer, cg()),
808
__FILE__, __LINE__, callNode);
809
}
810
cursor += sizeof(intptr_t);
811
812
return cursor;
813
}
814
815
void
816
TR_Debug::print(TR::FILE *pOutFile, TR::ARM64InterfaceCallSnippet * snippet)
817
{
818
TR::SymbolReference *callSymRef = snippet->getNode()->getSymbolReference();
819
uint8_t *cursor = snippet->getSnippetLabel()->getCodeLocation();
820
821
printSnippetLabel(pOutFile, snippet->getSnippetLabel(), cursor, getName(snippet), getName(callSymRef));
822
823
int32_t distance = getBLDistance(cursor);
824
printPrefix(pOutFile, NULL, cursor, ARM64_INSTRUCTION_LENGTH);
825
trfprintf(pOutFile, "bl \t" POINTER_PRINTF_FORMAT "\t\t; %s",
826
(intptr_t)cursor + distance, getRuntimeHelperName(TR_ARM64interfaceCallHelper));
827
cursor += ARM64_INSTRUCTION_LENGTH;
828
829
printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));
830
trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Code cache return address", *(intptr_t *)cursor);
831
cursor += sizeof(intptr_t);
832
833
printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));
834
trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Constant pool address", *(intptr_t *)cursor);
835
cursor += sizeof(intptr_t);
836
837
printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));
838
trfprintf(pOutFile, ".dword \t0x%08x\t\t; cpIndex", *(intptr_t *)cursor);
839
cursor += sizeof(intptr_t);
840
841
printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));
842
trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Interface class", *(intptr_t *)cursor);
843
cursor += sizeof(intptr_t);
844
845
printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));
846
trfprintf(pOutFile, ".dword \t0x%08x\t\t; itable index", *(intptr_t *)cursor);
847
cursor += sizeof(intptr_t);
848
849
printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));
850
trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; First Class Pointer", *(intptr_t *)cursor);
851
cursor += sizeof(intptr_t);
852
853
printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));
854
trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; First Class Target", *(intptr_t *)cursor);
855
cursor += sizeof(intptr_t);
856
857
printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));
858
trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Second Class Pointer", *(intptr_t *)cursor);
859
cursor += sizeof(intptr_t);
860
861
printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));
862
trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; Second Class Target", *(intptr_t *)cursor);
863
cursor += sizeof(intptr_t);
864
865
printPrefix(pOutFile, NULL, cursor, sizeof(intptr_t));
866
trfprintf(pOutFile, ".dword \t" POINTER_PRINTF_FORMAT "\t\t; J2I thunk address for private", *(intptr_t *)cursor);
867
}
868
869
uint32_t TR::ARM64InterfaceCallSnippet::getLength(int32_t estimatedSnippetStart)
870
{
871
/*
872
* (1 word for alignment)
873
* 1 instruction
874
* 10 address fields:
875
* - Code cache RA
876
* - CP Pointer
877
* - CP Index
878
* - Interface Class Pointer
879
* - ITable Index (may also contain a tagged J9Method* when handling nestmates)
880
* - First Class Pointer
881
* - First Class Target
882
* - Second Class Pointer
883
* - Second Class Target
884
* - J2I thunk address
885
*/
886
return ARM64_INSTRUCTION_LENGTH + sizeof(intptr_t)*10 + sizeof(int32_t);
887
}
888
889
uint8_t *TR::ARM64CallSnippet::generateVIThunk(TR::Node *callNode, int32_t argSize, TR::CodeGenerator *cg)
890
{
891
int32_t codeSize = 4 * (instructionCountForArguments(callNode, cg) + 5) + 8; // 5 instructions for branch, Additional 8 bytes to hold size of thunk
892
uint8_t *thunk, *buffer, *returnValue;
893
uintptr_t dispatcher;
894
895
if (cg->comp()->compileRelocatableCode())
896
thunk = (uint8_t *)cg->comp()->trMemory()->allocateMemory(codeSize, heapAlloc);
897
else
898
thunk = (uint8_t *)cg->allocateCodeMemory(codeSize, true, false);
899
buffer = returnValue = thunk + 8;
900
TR_RuntimeHelper helper;
901
TR::DataType dataType = callNode->getDataType();
902
903
switch (dataType)
904
{
905
case TR::NoType:
906
helper = TR_ARM64icallVMprJavaSendVirtual0;
907
break;
908
case TR::Int32:
909
helper = TR_ARM64icallVMprJavaSendVirtual1;
910
break;
911
case TR::Int64:
912
case TR::Address:
913
helper = TR_ARM64icallVMprJavaSendVirtualJ;
914
break;
915
case TR::Float:
916
helper = TR_ARM64icallVMprJavaSendVirtualF;
917
break;
918
case TR::Double:
919
helper = TR_ARM64icallVMprJavaSendVirtualD;
920
break;
921
default:
922
TR_ASSERT_FATAL(false, "Bad return data type '%s' for a call node.\n",
923
cg->getDebug()->getName(dataType));
924
}
925
926
#if defined(OSX)
927
pthread_jit_write_protect_np(0);
928
#endif
929
930
dispatcher = (uintptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(helper)->getMethodAddress();
931
932
buffer = flushArgumentsToStack(buffer, callNode, argSize, cg);
933
934
TR::RealRegister *x15reg = cg->machine()->getRealRegister(TR::RealRegister::x15);
935
936
*((int32_t *)thunk + 1) = buffer - returnValue; // patch offset for AOT relocation
937
// movz x15, low 16 bits
938
*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::movzx) | ((dispatcher & 0xFFFF) << 5);
939
x15reg->setRegisterFieldRD((uint32_t *)buffer);
940
buffer += ARM64_INSTRUCTION_LENGTH;
941
// movk x15, next 16 bits, lsl #16
942
*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::movkx) | (TR::MOV_LSL16 << 5) | (((dispatcher >> 16) & 0xFFFF) << 5);
943
x15reg->setRegisterFieldRD((uint32_t *)buffer);
944
buffer += ARM64_INSTRUCTION_LENGTH;
945
// movk x15, next 16 bits, lsl #32
946
*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::movkx) | (TR::MOV_LSL32 << 5) | (((dispatcher >> 32) & 0xFFFF) << 5);
947
x15reg->setRegisterFieldRD((uint32_t *)buffer);
948
buffer += ARM64_INSTRUCTION_LENGTH;
949
// movk x15, next 16 bits, lsl #48
950
*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::movkx) | (TR::MOV_LSL48 << 5) | (((dispatcher >> 48) & 0xFFFF) << 5);
951
x15reg->setRegisterFieldRD((uint32_t *)buffer);
952
buffer += ARM64_INSTRUCTION_LENGTH;
953
// br x15
954
*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::br);
955
x15reg->setRegisterFieldRN((uint32_t *)buffer);
956
buffer += ARM64_INSTRUCTION_LENGTH;
957
958
*(int32_t *)thunk = buffer - returnValue; // patch size of thunk
959
960
#ifdef TR_HOST_ARM64
961
arm64CodeSync(thunk, codeSize);
962
#endif
963
964
#if defined(OSX)
965
pthread_jit_write_protect_np(1);
966
#endif
967
968
return returnValue;
969
}
970
971
TR_J2IThunk *TR::ARM64CallSnippet::generateInvokeExactJ2IThunk(TR::Node *callNode, int32_t argSize, TR::CodeGenerator *cg, char *signature)
972
{
973
int32_t codeSize = 4 * (instructionCountForArguments(callNode, cg) + 5); // 5 instructions for branch
974
uintptr_t dispatcher;
975
TR::Compilation *comp = cg->comp();
976
TR_J2IThunkTable *thunkTable = comp->getPersistentInfo()->getInvokeExactJ2IThunkTable();
977
TR_J2IThunk *thunk = TR_J2IThunk::allocate(codeSize, signature, cg, thunkTable);
978
uint8_t *buffer = thunk->entryPoint();
979
980
TR_RuntimeHelper helper;
981
TR::DataType dataType = callNode->getDataType();
982
983
switch (dataType)
984
{
985
case TR::NoType:
986
helper = TR_icallVMprJavaSendInvokeExact0;
987
break;
988
case TR::Int32:
989
helper = TR_icallVMprJavaSendInvokeExact1;
990
break;
991
case TR::Int64:
992
case TR::Address:
993
helper = TR_icallVMprJavaSendInvokeExactJ;
994
break;
995
case TR::Float:
996
helper = TR_icallVMprJavaSendInvokeExactF;
997
break;
998
case TR::Double:
999
helper = TR_icallVMprJavaSendInvokeExactD;
1000
break;
1001
default:
1002
TR_ASSERT(false, "Bad return data type '%s' for a call node.\n",
1003
cg->getDebug()->getName(dataType));
1004
}
1005
1006
#if defined(OSX)
1007
pthread_jit_write_protect_np(0);
1008
#endif
1009
1010
dispatcher = (intptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(helper)->getMethodAddress();
1011
1012
buffer = flushArgumentsToStack(buffer, callNode, argSize, cg);
1013
1014
TR::RealRegister *x15reg = cg->machine()->getRealRegister(TR::RealRegister::x15);
1015
1016
// movz x15, low 16 bits
1017
*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::movzx) | ((dispatcher & 0xFFFF) << 5);
1018
x15reg->setRegisterFieldRD((uint32_t *)buffer);
1019
buffer += ARM64_INSTRUCTION_LENGTH;
1020
// movk x15, next 16 bits, lsl #16
1021
*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::movkx) | (TR::MOV_LSL16 << 5) | (((dispatcher >> 16) & 0xFFFF) << 5);
1022
x15reg->setRegisterFieldRD((uint32_t *)buffer);
1023
buffer += ARM64_INSTRUCTION_LENGTH;
1024
// movk x15, next 16 bits, lsl #32
1025
*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::movkx) | (TR::MOV_LSL32 << 5) | (((dispatcher >> 32) & 0xFFFF) << 5);
1026
x15reg->setRegisterFieldRD((uint32_t *)buffer);
1027
buffer += ARM64_INSTRUCTION_LENGTH;
1028
// movk x15, next 16 bits, lsl #48
1029
*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::movkx) | (TR::MOV_LSL48 << 5) | (((dispatcher >> 48) & 0xFFFF) << 5);
1030
x15reg->setRegisterFieldRD((uint32_t *)buffer);
1031
buffer += ARM64_INSTRUCTION_LENGTH;
1032
// br x15
1033
*(int32_t *)buffer = TR::InstOpCode::getOpCodeBinaryEncoding(TR::InstOpCode::br);
1034
x15reg->setRegisterFieldRN((uint32_t *)buffer);
1035
buffer += ARM64_INSTRUCTION_LENGTH;
1036
1037
#ifdef TR_HOST_ARM64
1038
arm64CodeSync(thunk->entryPoint(), codeSize);
1039
#endif
1040
1041
#if defined(OSX)
1042
pthread_jit_write_protect_np(1);
1043
#endif
1044
1045
return thunk;
1046
}
1047
1048
1049