Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/z/codegen/S390J9CallSnippet.cpp
6004 views
1
/*******************************************************************************
2
* Copyright (c) 2000, 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 "z/codegen/S390J9CallSnippet.hpp"
24
25
#include <stdint.h>
26
#include "codegen/CodeGenerator.hpp"
27
#include "codegen/InstOpCode.hpp"
28
#include "env/CompilerEnv.hpp"
29
#include "env/IO.hpp"
30
#include "env/J2IThunk.hpp"
31
#include "env/jittypes.h"
32
#include "env/VMJ9.h"
33
#include "env/VerboseLog.hpp"
34
#include "il/LabelSymbol.hpp"
35
#include "il/Node.hpp"
36
#include "il/Node_inlines.hpp"
37
#include "runtime/CodeCacheManager.hpp"
38
#include "runtime/Runtime.hpp"
39
#include "runtime/RuntimeAssumptions.hpp"
40
41
uint8_t *
42
TR::S390J9CallSnippet::generateVIThunk(TR::Node * callNode, int32_t argSize, TR::CodeGenerator * cg)
43
{
44
TR::Compilation *comp = cg->comp();
45
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());
46
int32_t lengthOfVIThunk = (comp->target().is64Bit()) ? 18 : 12;
47
int32_t codeSize = instructionCountForArguments(callNode, cg) + lengthOfVIThunk;
48
uint32_t rEP = (uint32_t) cg->getEntryPointRegister() - 1;
49
50
// make it double-word aligned
51
codeSize = (codeSize + 7) / 8 * 8 + 8; // Additional 4 bytes to hold size of thunk
52
uint8_t * thunk, * cursor, * returnValue;
53
TR::SymbolReference *dispatcherSymbol;
54
55
if (fej9->storeOffsetToArgumentsInVirtualIndirectThunks())
56
thunk = (uint8_t *)comp->trMemory()->allocateMemory(codeSize, heapAlloc);
57
else
58
thunk = (uint8_t *)cg->allocateCodeMemory(codeSize, true);
59
60
cursor = returnValue = thunk + 8;
61
62
switch (callNode->getDataType())
63
{
64
case TR::NoType:
65
dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_S390icallVMprJavaSendVirtual0);
66
break;
67
case TR::Int32:
68
dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_S390icallVMprJavaSendVirtual1);
69
break;
70
case TR::Address:
71
if (comp->target().is64Bit())
72
{
73
dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_S390icallVMprJavaSendVirtualJ);
74
}
75
else
76
{
77
dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_S390icallVMprJavaSendVirtual1);
78
}
79
80
break;
81
case TR::Int64:
82
dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_S390icallVMprJavaSendVirtualJ);
83
break;
84
case TR::Float:
85
dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_S390icallVMprJavaSendVirtualF);
86
break;
87
case TR::Double:
88
dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_S390icallVMprJavaSendVirtualD);
89
break;
90
default:
91
TR_ASSERT(0, "Bad return data type for a call node. DataType was %s\n",
92
comp->getDebug()->getName(callNode->getDataType()));
93
}
94
95
cursor = S390flushArgumentsToStack(cursor, callNode, argSize, cg);
96
97
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
98
// if you change the following code,
99
// make sure 'lengthOfVIThunk' and hence 'codeSize' defined above
100
// are large enough to cover the VIThunk code.
101
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
102
// branch to the dispatcher
103
//
104
// 0d40 BASR rEP,0
105
// 5840 400a L rEP,6(,rEP) or LG rEP, 6(,rEP) for 64bit
106
// 0de4 BCR ,rEP
107
// <method address>
108
109
*(int16_t *) cursor = 0x0d00 + (((int16_t) rEP) << 4); // BASR rEP,0
110
cursor += 2;
111
if (comp->target().is64Bit())
112
{
113
*(uint32_t *) cursor = 0xe3000008 + (rEP << 12) + (rEP << 20); // LG rEP,8(,rEP)
114
cursor += 4;
115
*(uint16_t *) cursor = 0x0004;
116
cursor += 2;
117
}
118
else
119
{
120
*(int32_t *) cursor = 0x58000006 + (rEP << 12) + (rEP << 20); // L rEP,6(,rEP)
121
cursor += 4;
122
}
123
124
*(int16_t *) cursor = 0x07f0 + (int16_t) rEP; // BCR rEP
125
cursor += 2;
126
127
*((int32_t *)thunk + 1) = cursor - returnValue; // patch offset for AOT relocation
128
129
*(uintptr_t *) cursor = (uintptr_t) dispatcherSymbol->getMethodAddress();
130
131
cursor += sizeof(uintptr_t);
132
133
*(int32_t *)thunk = cursor - returnValue; // patch size of thunk
134
135
return returnValue;
136
}
137
138
TR_J2IThunk *
139
TR::S390J9CallSnippet::generateInvokeExactJ2IThunk(TR::Node * callNode, int32_t argSize, char* signature, TR::CodeGenerator * cg)
140
{
141
uint32_t rEP = (uint32_t) cg->getEntryPointRegister() - 1;
142
TR::Compilation *comp = cg->comp();
143
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());
144
bool verbose = comp->getOptions()->getVerboseOption(TR_VerboseJ2IThunks);
145
int32_t finalCallLength = verbose? 6 : 2;
146
int32_t lengthOfIEThunk = finalCallLength + (comp->target().is64Bit() ? 16 : 10);
147
int32_t codeSize = instructionCountForArguments(callNode, cg) + lengthOfIEThunk;
148
// TODO:JSR292: VI thunks have code to ensure they are double-word aligned. Do we need that here?
149
150
TR_J2IThunkTable *thunkTable = comp->getPersistentInfo()->getInvokeExactJ2IThunkTable();
151
TR_J2IThunk *thunk = TR_J2IThunk::allocate(codeSize, signature, cg, thunkTable);
152
uint8_t *cursor = thunk->entryPoint();
153
154
TR::SymbolReference *dispatcherSymbol;
155
switch (callNode->getDataType())
156
{
157
case TR::NoType:
158
dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExact0);
159
break;
160
case TR::Int32:
161
dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExact1);
162
break;
163
case TR::Address:
164
if (comp->target().is64Bit())
165
dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExactJ);
166
else
167
dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExact1);
168
break;
169
case TR::Int64:
170
dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExactJ);
171
break;
172
case TR::Float:
173
dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExactF);
174
break;
175
case TR::Double:
176
dispatcherSymbol = cg->symRefTab()->findOrCreateRuntimeHelper(TR_icallVMprJavaSendInvokeExactD);
177
break;
178
default:
179
TR_ASSERT(0, "Bad return data type for a call node. DataType was %s\n",
180
comp->getDebug()->getName(callNode->getDataType()));
181
}
182
183
cursor = S390flushArgumentsToStack(cursor, callNode, argSize, cg);
184
185
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
186
// if you change the following code,
187
// make sure 'lengthOfVIThunk' and hence 'codeSize' defined above
188
// are large enough to cover the VIThunk code.
189
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
190
// branch to the dispatcher
191
//
192
// 0d40 BASR rEP,0
193
// 5840 400a L rEP,6(,rEP) or LG rEP, 8(,rEP) for 64bit
194
// 0de4 BCR ,rEP -- OR CALL TO methodHandleJ2IGlue --
195
// <method address>
196
197
*(int16_t *) cursor = 0x0d00 + (((int16_t) rEP) << 4); // BASR rEP,0
198
cursor += 2;
199
if (comp->target().is64Bit())
200
{
201
*(uint32_t *) cursor = 0xe3000006 + finalCallLength + (rEP << 12) + (rEP << 20); // LG rEP,8(,rEP)
202
cursor += 4;
203
*(uint16_t *) cursor = 0x0004;
204
cursor += 2;sizeof(int16_t);
205
}
206
else
207
{
208
*(int32_t *) cursor = 0x58000004 + finalCallLength + (rEP << 12) + (rEP << 20); // L rEP,6(,rEP)
209
cursor += 4;
210
}
211
212
uintptr_t helperAddress = (uintptr_t)dispatcherSymbol->getMethodAddress();
213
if (verbose)
214
{
215
*(int16_t *) cursor = 0xC0F4; // BRCL <Helper Addr>
216
cursor += 2;
217
218
TR::SymbolReference *helper = cg->symRefTab()->findOrCreateRuntimeHelper(TR_methodHandleJ2IGlue);
219
intptr_t destAddr = (intptr_t)helper->getMethodAddress();
220
#if defined(TR_TARGET_64BIT)
221
#if defined(J9ZOS390)
222
if (comp->getOption(TR_EnableRMODE64))
223
#endif
224
{
225
if (NEEDS_TRAMPOLINE(destAddr, cursor, cg))
226
destAddr = TR::CodeCacheManager::instance()->findHelperTrampoline(helper->getReferenceNumber(), (void *)cursor);
227
}
228
#endif
229
TR_ASSERT(CHECK_32BIT_TRAMPOLINE_RANGE(destAddr, cursor), "Helper Call must be reachable");
230
*(int32_t *) cursor = (int32_t)((destAddr - (intptr_t)(cursor - 2)) / 2);
231
cursor += 4;
232
}
233
else
234
{
235
*(int16_t *) cursor = 0x07f0 + (int16_t) rEP; // BCR rEP
236
cursor += 2;
237
}
238
239
*(uintptr_t *) cursor = (uintptr_t) cg->fej9()->getInvokeExactThunkHelperAddress(comp, dispatcherSymbol, callNode->getDataType());
240
cursor += sizeof(uintptr_t);
241
242
diagnostic("\n-- ( Created invokeExact J2I thunk " POINTER_PRINTF_FORMAT " for node " POINTER_PRINTF_FORMAT " )", thunk, callNode);
243
244
TR_ASSERT(cursor == thunk->entryPoint() + codeSize, "Must allocate correct amount of memory for invokeExact J2I thunk %p. Allocated %d bytes but consumed %d = %d plus argument spills", thunk->entryPoint(), codeSize, cursor - thunk->entryPoint(), lengthOfIEThunk);
245
246
if (verbose)
247
TR_VerboseLog::writeLineLocked(TR_Vlog_J2I, "Created J2I thunk %s @ %p while compiling %s", thunk->terseSignature(), thunk->entryPoint(), comp->signature());
248
249
return thunk;
250
}
251
252
253
uint8_t *
254
TR::S390J9CallSnippet::emitSnippetBody()
255
{
256
TR::Compilation *comp = cg()->comp();
257
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());
258
259
uint8_t * cursor = cg()->getBinaryBufferCursor();
260
TR::Node * callNode = getNode();
261
TR::SymbolReference * methodSymRef = getRealMethodSymbolReference();
262
263
if (!methodSymRef)
264
methodSymRef = callNode->getSymbolReference();
265
266
TR::MethodSymbol * methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();
267
268
AOTcgDiag1(comp, "TR::S390CallSnippet::emitSnippetBody cursor=%x\n", cursor);
269
getSnippetLabel()->setCodeLocation(cursor);
270
271
// Flush in-register arguments back to the stack for interpreter
272
cursor = S390flushArgumentsToStack(cursor, callNode, getSizeOfArguments(), cg());
273
274
TR_RuntimeHelper runtimeHelper = getInterpretedDispatchHelper(methodSymRef, callNode->getDataType());
275
TR::SymbolReference * glueRef = cg()->symRefTab()->findOrCreateRuntimeHelper(runtimeHelper);
276
277
// Generate RIOFF if RI is supported.
278
cursor = generateRuntimeInstrumentationOnOffInstruction(cg(), cursor, TR::InstOpCode::RIOFF);
279
280
// data area start address
281
uintptr_t dataStartAddr = (uintptr_t) (getPICBinaryLength() + cursor);
282
283
// calculate pad bytes to get the data area aligned
284
int32_t pad_bytes = (dataStartAddr + (sizeof(uintptr_t) - 1)) / sizeof(uintptr_t) * sizeof(uintptr_t) - dataStartAddr;
285
286
setPadBytes(pad_bytes);
287
288
// branch to the glueRef
289
//
290
// 0d40 BASR rEP,0
291
// 5840 4006 L rEP,6(,rEP) LG rEP, 8(rEP) for 64bit
292
// 0de4 BASR r14,rEP
293
294
cursor = generatePICBinary(cursor, glueRef);
295
296
// add NOPs to make sure the data area is aligned
297
if (pad_bytes == 2)
298
{
299
*(int16_t *) cursor = 0x0000; // padding 2-bytes
300
cursor += 2;
301
}
302
else if (comp->target().is64Bit())
303
{
304
if (pad_bytes == 4) // padding 4-bytes
305
{
306
*(int32_t *) cursor = 0x00000000;
307
cursor += 4;
308
}
309
else if (pad_bytes == 6) // padding 6-bytes
310
{
311
*(int32_t *) cursor = 0x00000000;
312
cursor += 4;
313
*(uint16_t *) cursor = 0x0000;
314
cursor += 2;
315
}
316
}
317
318
// Data Area
319
// <method address>
320
// code cache RA
321
// method pointer
322
323
pad_bytes = (((uintptr_t) cursor + (sizeof(uintptr_t) - 1)) / sizeof(uintptr_t) * sizeof(uintptr_t) - (uintptr_t) cursor);
324
TR_ASSERT( pad_bytes == 0, "Method address field must be aligned for patching");
325
326
// Method address
327
*(uintptr_t *) cursor = (uintptr_t) glueRef->getMethodAddress();
328
AOTcgDiag1(comp, "add TR_AbsoluteHelperAddress cursor=%x\n", cursor);
329
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, (uint8_t *)glueRef, TR_AbsoluteHelperAddress, cg()),
330
__FILE__, __LINE__, callNode);
331
cursor += sizeof(uintptr_t);
332
333
// Store the code cache RA
334
*(uintptr_t *) cursor = (uintptr_t) getCallRA();
335
AOTcgDiag1(comp, "add TR_AbsoluteMethodAddress cursor=%x\n", cursor);
336
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, NULL, TR_AbsoluteMethodAddress, cg()),
337
__FILE__, __LINE__, callNode);
338
cursor += sizeof(uintptr_t);
339
340
//induceOSRAtCurrentPC is implemented in the VM, and it knows, by looking at the current PC, what method it needs to
341
//continue execution in interpreted mode. Therefore, it doesn't need the method pointer.
342
if (!glueRef->isOSRInductionHelper())
343
{
344
// Store the method pointer: it is NULL for unresolved
345
// This field must be doubleword aligned for 64-bit and word aligned for 32-bit
346
if (methodSymRef->isUnresolved() || (comp->compileRelocatableCode() && !comp->getOption(TR_UseSymbolValidationManager)))
347
{
348
pad_bytes = (((uintptr_t) cursor + (sizeof(uintptr_t) - 1)) / sizeof(uintptr_t) * sizeof(uintptr_t) - (uintptr_t) cursor);
349
TR_ASSERT( pad_bytes == 0, "Method Pointer field must be aligned for patching");
350
*(uintptr_t *) cursor = 0;
351
if (comp->getOption(TR_EnableHCR))
352
{
353
//TODO check what happens when we pass -1 to jitAddPicToPatchOnClassRedefinition an dif it's correct in this case
354
cg()->jitAddPicToPatchOnClassRedefinition((void*)-1, (void *)cursor, true);
355
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation((uint8_t *)cursor, NULL,
356
TR_HCR, cg()),__FILE__, __LINE__, getNode());
357
}
358
}
359
else
360
{
361
uintptr_t ramMethod = (uintptr_t)methodSymRef->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod()->getPersistentIdentifier();
362
*(uintptr_t *) cursor = ramMethod;
363
if (comp->getOption(TR_EnableHCR))
364
cg()->jitAddPicToPatchOnClassRedefinition((void *)methodSymbol->getMethodAddress(), (void *)cursor);
365
AOTcgDiag1(comp, "add TR_MethodObject cursor=%x\n", cursor);
366
if (comp->getOption(TR_UseSymbolValidationManager))
367
{
368
TR_ASSERT_FATAL(ramMethod, "cursor = %x, ramMehtod can not be null", cursor);
369
cg()->addExternalRelocation( new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor,
370
(uint8_t *)ramMethod,
371
(uint8_t *)TR::SymbolType::typeMethod,
372
TR_SymbolFromManager,
373
cg()),
374
__FILE__, __LINE__, callNode);
375
}
376
#if defined(J9VM_OPT_JITSERVER)
377
else if (!comp->isOutOfProcessCompilation()) // Since we query this information from the client, remote compilations don't need to add relocation records for TR_MethodObject
378
#else
379
else
380
#endif /* defined(J9VM_OPT_JITSERVER) */
381
{
382
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, (uint8_t *) callNode->getSymbolReference(), getNode() ? (uint8_t *)(intptr_t)getNode()->getInlinedSiteIndex() : (uint8_t *)-1, TR_MethodObject, cg()),
383
__FILE__, __LINE__, callNode);
384
}
385
}
386
}
387
388
return cursor + sizeof(uintptr_t);
389
}
390
391
TR_RuntimeHelper TR::S390J9CallSnippet::getInterpretedDispatchHelper(TR::SymbolReference *methodSymRef, TR::DataType type)
392
{
393
TR::Compilation *comp = cg()->comp();
394
TR::MethodSymbol * methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();
395
bool isJitInduceOSRCall = false;
396
if (methodSymbol->isHelper() &&
397
methodSymRef->isOSRInductionHelper())
398
{
399
isJitInduceOSRCall = true;
400
}
401
402
if (methodSymRef->isUnresolved() || (comp->compileRelocatableCode() && !comp->getOption(TR_UseSymbolValidationManager)))
403
{
404
TR_ASSERT(!isJitInduceOSRCall || !comp->compileRelocatableCode(), "calling jitInduceOSR is not supported yet under AOT\n");
405
if (methodSymbol->isStatic())
406
return TR_S390interpreterUnresolvedStaticGlue;
407
else
408
return TR_S390interpreterUnresolvedSpecialGlue;
409
}
410
else if (isJitInduceOSRCall)
411
{
412
return (TR_RuntimeHelper) methodSymRef->getReferenceNumber();
413
}
414
else if (methodSymbol->isVMInternalNative() || methodSymbol->isJITInternalNative())
415
{
416
return TR_S390nativeStaticHelper;
417
}
418
else
419
{
420
return TR_S390interpreterStaticSpecialCallGlue;
421
}
422
}
423
424
uint32_t
425
TR::S390J9CallSnippet::getPICBinaryLength()
426
{
427
if (self()->getKind() == TR::Snippet::IsUnresolvedCall)
428
return 14; /* LARL + LG/LGF + BCR */
429
else
430
return 6;
431
}
432
433
uint8_t *
434
TR::S390J9CallSnippet::generatePICBinary(uint8_t * cursor, TR::SymbolReference* glueRef)
435
{
436
// Branch to the dispatcher.
437
// Since N3 instructions are supported, we can use relative long instructions.
438
// i.e.:
439
// BRASL r14, <target Addr>.
440
// - or -
441
// LARL r14, <target Addr>. // Unresolved Calls only.
442
// LG/LGF rEP, 0(r14).
443
// BCR rEP
444
uint32_t rEP = (uint32_t) cg()->getEntryPointRegister() - 1;
445
446
if (self()->getKind() == TR::Snippet::IsUnresolvedCall)
447
{
448
// Generate LARL r14, <Start of Data Const>
449
*(int16_t *) cursor = 0xC0E0;
450
cursor += sizeof(int16_t);
451
intptr_t destAddr = (intptr_t)(cursor + getPICBinaryLength() + self()->getPadBytes() - 2);
452
*(int32_t *) cursor = (int32_t)((destAddr - (intptr_t)(cursor - 2)) / 2);
453
cursor += sizeof(int32_t);
454
455
*(int32_t *) cursor = 0xe300e000 + (rEP << 20); // LG/F rEP, 0(r14)
456
cursor += sizeof(int32_t);
457
*(int16_t *) cursor = cg()->comp()->target().is64Bit() ? 0x0004 : 0x0014;
458
cursor += sizeof(int16_t);
459
460
// BCR rEP
461
*(int16_t *) cursor = 0x07F0 + rEP;
462
cursor += sizeof(int16_t);
463
}
464
else
465
{
466
// Generate BRASL instruction.
467
intptr_t instructionStartAddress = (intptr_t)cursor;
468
*(int16_t *) cursor = 0xC0E5;
469
cursor += sizeof(int16_t);
470
471
// Calculate the relative offset to get to helper method.
472
// If MCC is not supported, everything should be reachable.
473
// If MCC is supported, we will look up the appropriate trampoline, if
474
// necessary.
475
intptr_t destAddr = (intptr_t)(glueRef->getSymbol()->castToMethodSymbol()->getMethodAddress());
476
477
#if defined(TR_TARGET_64BIT)
478
#if defined(J9ZOS390)
479
if (cg()->comp()->getOption(TR_EnableRMODE64))
480
#endif
481
{
482
if (cg()->directCallRequiresTrampoline(destAddr, instructionStartAddress))
483
{
484
// Destination is beyond our reachable jump distance, we'll find the
485
// trampoline.
486
destAddr = TR::CodeCacheManager::instance()->findHelperTrampoline(glueRef->getReferenceNumber(), (void *)cursor);
487
self()->setUsedTrampoline(true);
488
}
489
}
490
#endif
491
492
TR_ASSERT_FATAL(cg()->comp()->target().cpu.isTargetWithinBranchRelativeRILRange(destAddr, instructionStartAddress),
493
"Helper Call is not reachable.");
494
self()->setSnippetDestAddr(destAddr);
495
496
*(int32_t *) cursor = (int32_t)((destAddr - instructionStartAddress) / 2);
497
AOTcgDiag1(cg()->comp(), "add TR_AbsoluteHelperAddress cursor=%x\n", cursor);
498
cg()->addProjectSpecializedRelocation(cursor, (uint8_t*) glueRef, NULL, TR_HelperAddress,
499
__FILE__, __LINE__, self()->getNode());
500
cursor += sizeof(int32_t);
501
}
502
return cursor;
503
}
504
505
uint32_t
506
TR::S390J9CallSnippet::getLength(int32_t estimatedSnippetStart)
507
{
508
// *this swipeable for debugger
509
// length = instructionCountForArgsInBytes + (BASR + L(or LG) + BASR +3*sizeof(uintptr_t)) + NOPs
510
// number of pad bytes has not been set when this method is called to
511
// estimate codebuffer size, so -- i'll put an conservative number here...
512
return (instructionCountForArguments(getNode(), cg()) +
513
getPICBinaryLength() +
514
3 * sizeof(uintptr_t) +
515
getRuntimeInstrumentationOnOffInstructionLength(cg()) +
516
sizeof(uintptr_t)); // the last item is for padding
517
}
518
519
void
520
TR::S390J9CallSnippet::print(TR::FILE *pOutFile, TR_Debug *debug)
521
{
522
uint8_t * bufferPos = getSnippetLabel()->getCodeLocation();
523
TR::Node * callNode = getNode();
524
TR::SymbolReference * methodSymRef = getRealMethodSymbolReference();
525
if(!methodSymRef)
526
methodSymRef = callNode->getSymbolReference();
527
528
TR::MethodSymbol * methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();
529
TR::SymbolReference * glueRef;
530
int8_t padbytes = getPadBytes();
531
532
debug->printSnippetLabel(pOutFile, getSnippetLabel(), bufferPos,
533
methodSymRef->isUnresolved() ? "Unresolved Call Snippet" : "Call Snippet");
534
535
bufferPos = debug->printS390ArgumentsFlush(pOutFile, callNode, bufferPos, getSizeOfArguments());
536
537
if (methodSymRef->isUnresolved() || (cg()->comp()->compileRelocatableCode() && !cg()->comp()->getOption(TR_UseSymbolValidationManager)))
538
{
539
if (methodSymbol->isStatic())
540
glueRef = cg()->getSymRef(TR_S390interpreterUnresolvedStaticGlue);
541
else
542
glueRef = cg()->getSymRef(TR_S390interpreterUnresolvedSpecialGlue);
543
}
544
else if ((methodSymbol->isVMInternalNative() || methodSymbol->isJITInternalNative()))
545
{
546
glueRef = cg()->getSymRef(TR_S390nativeStaticHelper);
547
}
548
else
549
{
550
glueRef = cg()->getSymRef(TR_S390interpreterStaticSpecialCallGlue);
551
}
552
553
bufferPos = debug->printRuntimeInstrumentationOnOffInstruction(pOutFile, bufferPos, false); // RIOFF
554
555
if (getKind() == TR::Snippet::IsUnresolvedCall)
556
{
557
debug->printPrefix(pOutFile, NULL, bufferPos, 6);
558
trfprintf(pOutFile, "LARL \tGPR14, *+%d <%p>\t# Start of Data Const.",
559
8 + 6 + padbytes,
560
bufferPos + 8 + 6 + padbytes);
561
bufferPos += 6;
562
debug->printPrefix(pOutFile, NULL, bufferPos, 6);
563
trfprintf(pOutFile, cg()->comp()->target().is64Bit() ? "LG \tGPR_EP, 0(,GPR14)" : "LGF \tGPR_EP, 0(,GPR14");
564
bufferPos += 6;
565
566
debug->printPrefix(pOutFile, NULL, bufferPos, 2);
567
trfprintf(pOutFile, "BCR \tGPR_EP");
568
bufferPos += 2;
569
}
570
else
571
{
572
debug->printPrefix(pOutFile, NULL, bufferPos, 6);
573
trfprintf(pOutFile, "BRASL \tGPR14, <%p>\t# Branch to Helper Method %s",
574
getSnippetDestAddr(),
575
usedTrampoline() ? "- Trampoline Used.":"");
576
bufferPos += 6;
577
}
578
579
if (padbytes == 2)
580
{
581
debug->printPrefix(pOutFile, NULL, bufferPos, 2);
582
trfprintf(pOutFile, "DC \t0x0000 \t\t\t# 2-bytes padding for alignment");
583
bufferPos += 2;
584
}
585
else if (padbytes == 4)
586
{
587
debug->printPrefix(pOutFile, NULL, bufferPos, 4) ;
588
trfprintf(pOutFile, "DC \t0x00000000 \t\t# 4-bytes padding for alignment");
589
bufferPos += 4;
590
}
591
else if (padbytes == 6)
592
{
593
debug->printPrefix(pOutFile, NULL, bufferPos, 6) ;
594
trfprintf(pOutFile, "DC \t0x000000000000 \t\t# 6-bytes padding for alignment");
595
bufferPos += 6;
596
}
597
598
debug->printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
599
trfprintf(pOutFile, "DC \t%p \t\t# Method Address", glueRef->getMethodAddress());
600
bufferPos += sizeof(intptr_t);
601
602
603
debug->printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
604
trfprintf(pOutFile, "DC \t%p \t\t# Call Site RA", getCallRA());
605
bufferPos += sizeof(intptr_t);
606
607
if (methodSymRef->isUnresolved())
608
{
609
debug->printPrefix(pOutFile, NULL, bufferPos, 0);
610
}
611
else
612
{
613
debug->printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
614
}
615
trfprintf(pOutFile, "DC \t%p \t\t# Method Pointer", methodSymRef->isUnresolved() ? 0 : methodSymbol->getMethodAddress());
616
}
617
618
uint8_t *
619
TR::S390UnresolvedCallSnippet::emitSnippetBody()
620
{
621
TR::Compilation *comp = cg()->comp();
622
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());
623
624
uint8_t * cursor = TR::S390J9CallSnippet::emitSnippetBody();
625
626
TR::SymbolReference * methodSymRef = getNode()->getSymbolReference();
627
TR::MethodSymbol * methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();
628
int32_t helperLookupOffset;
629
630
switch (getNode()->getDataType())
631
{
632
case TR::NoType:
633
helperLookupOffset = 0;
634
break;
635
case TR::Int32:
636
helperLookupOffset = TR::Compiler->om.sizeofReferenceAddress();
637
break;
638
case TR::Address:
639
if (comp->target().is64Bit())
640
{
641
helperLookupOffset = 2 * TR::Compiler->om.sizeofReferenceAddress();
642
}
643
else
644
{
645
helperLookupOffset = TR::Compiler->om.sizeofReferenceAddress();
646
}
647
648
break;
649
case TR::Int64:
650
helperLookupOffset = 2 * TR::Compiler->om.sizeofReferenceAddress();
651
break;
652
case TR::Float:
653
helperLookupOffset = 3 * TR::Compiler->om.sizeofReferenceAddress();
654
break;
655
case TR::Double:
656
helperLookupOffset = 4 * TR::Compiler->om.sizeofReferenceAddress();
657
break;
658
}
659
660
// Constant Pool
661
*(uintptr_t *) cursor = (uintptr_t) methodSymRef->getOwningMethod(comp)->constantPool();
662
AOTcgDiag1(comp, "add TR_ConstantPool cursor=%x\n", cursor);
663
664
#if defined(TR_TARGET_64BIT)
665
#if defined(J9ZOS390)
666
if (comp->getOption(TR_EnableRMODE64))
667
#endif
668
{
669
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, *(uint8_t **)cursor, getNode() ? (uint8_t *)(intptr_t)getNode()->getInlinedSiteIndex() : (uint8_t *)-1,
670
TR_Trampolines, cg()),
671
__FILE__, __LINE__,getNode());
672
}
673
#if defined(J9ZOS390)
674
else
675
{
676
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, *(uint8_t **)cursor, getNode() ? (uint8_t *)getNode()->getInlinedSiteIndex() : (uint8_t *)-1, TR_ConstantPool, cg()),
677
__FILE__, __LINE__, getNode());
678
}
679
#endif
680
#else
681
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, *(uint8_t **)cursor, getNode() ? (uint8_t *)getNode()->getInlinedSiteIndex() : (uint8_t *)-1, TR_ConstantPool, cg()),
682
__FILE__, __LINE__, getNode());
683
#endif
684
685
cursor += sizeof(uintptr_t);
686
687
// Constant Pool Index
688
*(uint32_t *) cursor = (helperLookupOffset << 24) | methodSymRef->getCPIndexForVM();
689
690
#if defined(TR_TARGET_64BIT)
691
#if defined(J9ZOS390)
692
if (comp->getOption(TR_EnableRMODE64))
693
#endif
694
{
695
if ((comp->compileRelocatableCode() || comp->isOutOfProcessCompilation()) && comp->getOption(TR_TraceRelocatableDataDetailsCG))
696
{
697
traceMsg(comp, "<relocatableDataTrampolinesCG>\n");
698
traceMsg(comp, "%s\n", comp->signature());
699
traceMsg(comp, "%-8s", "cpIndex");
700
traceMsg(comp, "cp\n");
701
traceMsg(comp, "%-8x", methodSymRef->getCPIndexForVM());
702
traceMsg(comp, "%x\n", methodSymRef->getOwningMethod(comp)->constantPool());
703
traceMsg(comp, "</relocatableDataTrampolinesCG>\n");
704
}
705
}
706
#endif
707
708
return cursor + sizeof(int32_t);
709
}
710
711
uint32_t
712
TR::S390UnresolvedCallSnippet::getLength(int32_t estimatedSnippetStart)
713
{
714
return TR::S390J9CallSnippet::getLength(estimatedSnippetStart) + sizeof(uintptr_t) + sizeof(int32_t);
715
}
716
717
uint8_t *
718
TR::S390VirtualSnippet::emitSnippetBody()
719
{
720
return NULL;
721
}
722
723
uint32_t
724
TR::S390VirtualSnippet::getLength(int32_t estimatedSnippetStart)
725
{
726
return 0;
727
}
728
729
uint8_t *
730
TR::S390VirtualUnresolvedSnippet::emitSnippetBody()
731
{
732
uint8_t * cursor = cg()->getBinaryBufferCursor();
733
TR::Node * callNode = getNode();
734
TR::Compilation *comp = cg()->comp();
735
TR::SymbolReference * glueRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_S390virtualUnresolvedHelper);
736
737
getSnippetLabel()->setCodeLocation(cursor);
738
739
// Generate RIOFF if RI is supported.
740
cursor = generateRuntimeInstrumentationOnOffInstruction(cg(), cursor, TR::InstOpCode::RIOFF);
741
742
cursor = generatePICBinary(cursor, glueRef);
743
744
745
// Method address
746
*(uintptr_t *) cursor = (uintptr_t) glueRef->getMethodAddress();
747
AOTcgDiag1(comp, "add TR_AbsoluteHelperAddress cursor=%x\n", cursor);
748
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, (uint8_t *)glueRef, TR_AbsoluteHelperAddress, cg()),
749
__FILE__, __LINE__, callNode);
750
cursor += sizeof(uintptr_t);
751
752
// Store the code cache RA
753
*(uintptr_t *) cursor = (uintptr_t) getCallRA();
754
AOTcgDiag1(comp, "add TR_AbsoluteMethodAddress cursor=%x\n", cursor);
755
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, NULL, TR_AbsoluteMethodAddress, cg()),
756
__FILE__, __LINE__, callNode);
757
cursor += sizeof(uintptr_t);
758
759
// CP addr
760
*(uintptr_t *) cursor = (uintptr_t) callNode->getSymbolReference()->getOwningMethod(comp)->constantPool();
761
762
// J2I relocation information for private nestmate calls
763
auto j2iRelocInfo = reinterpret_cast<TR_RelocationRecordInformation*>(comp->trMemory()->allocateMemory(sizeof(TR_RelocationRecordInformation), heapAlloc));
764
j2iRelocInfo->data1 = *(uintptr_t *) cursor; // CP address
765
j2iRelocInfo->data2 = (uintptr_t)(callNode ? callNode->getInlinedSiteIndex() : -1); // inlined site index
766
uintptr_t cpAddrPosition = (uintptr_t)cursor; // for data3 calculation
767
cursor += sizeof(uintptr_t);
768
769
// save CPIndex as sign extended 8 byte value on 64bit as it's assumed in J9 helpers -- def#63837
770
*(uintptr_t *) cursor = (uintptr_t) callNode->getSymbolReference()->getCPIndexForVM();
771
cursor += TR::Compiler->om.sizeofReferenceAddress();
772
773
// instruction to be patched
774
*(uintptr_t *) cursor = (uintptr_t) (getPatchVftInstruction()->getBinaryEncoding());
775
AOTcgDiag1(comp, "add TR_AbsoluteMethodAddress cursor=%x\n", cursor);
776
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, NULL, TR_AbsoluteMethodAddress, cg()),
777
__FILE__, __LINE__, callNode);
778
cursor += sizeof(uintptr_t);
779
780
// Field used by nestmate private calls
781
// J9Method pointer of the callee. Initialized to 0.
782
*(uintptr_t *) cursor = 0;
783
cursor += sizeof(uintptr_t);
784
785
// Field used by nestmate private calls
786
// J2I thunk address
787
// No explicit call to `addExternalRelocation` because its relocation info is passed to CP_addr `addExternalRelocation` call.
788
*(uintptr_t *) cursor = (uintptr_t) thunkAddress;
789
j2iRelocInfo->data3 = (uintptr_t)cursor - cpAddrPosition; // data3 is the offset of CP_addr to J2I thunk
790
AOTcgDiag1(comp, "add TR_J2IVirtualThunkPointer cursor=%x\n", cursor);
791
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation((uint8_t*)cpAddrPosition, (uint8_t*)j2iRelocInfo, NULL,
792
TR_J2IVirtualThunkPointer, cg()),
793
__FILE__, __LINE__, callNode);
794
cursor += sizeof(uintptr_t);
795
796
// Field used by nestmate private calls
797
// For private functions, this is the return address.
798
// Add a 2 bytes off set because it's the instruction after the BASR, which is 2-byte long
799
// The assumption here is that S390 J9 private linkage indirect dispatch is emitting BASR.
800
TR_ASSERT_FATAL(getIndirectCallInstruction() && getIndirectCallInstruction()->getOpCodeValue() == TR::InstOpCode::BASR,
801
"Unexpected branch instruction in VirtualUnresolvedSnippet.\n");
802
803
*(uintptr_t *) cursor = (uintptr_t) (getIndirectCallInstruction()->getBinaryEncoding() + getIndirectCallInstruction()->getBinaryLength());
804
AOTcgDiag1(comp, "add PrivateRA cursor=%x\n", cursor);
805
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, NULL, TR_AbsoluteMethodAddress, cg()),
806
__FILE__, __LINE__, callNode);
807
808
cursor += sizeof(uintptr_t);
809
810
return cursor;
811
}
812
813
uint32_t
814
TR::S390VirtualUnresolvedSnippet::getLength(int32_t estimatedSnippetStart)
815
{
816
TR::Compilation* comp = cg()->comp();
817
uint32_t length = getPICBinaryLength() + 7 * sizeof(uintptr_t) + TR::Compiler->om.sizeofReferenceAddress();
818
length += getRuntimeInstrumentationOnOffInstructionLength(cg());
819
return length;
820
}
821
822
TR::S390InterfaceCallSnippet::S390InterfaceCallSnippet(
823
TR::CodeGenerator *cg,
824
TR::Node *c,
825
TR::LabelSymbol *lab,
826
int32_t s,
827
int8_t n,
828
void *thunkPtr,
829
bool useCLFIandBRCL)
830
: TR::S390VirtualSnippet(cg, c, lab, s),
831
_numInterfaceCallCacheSlots(n),
832
_useCLFIandBRCL(useCLFIandBRCL)
833
{
834
_dataSnippet = new (cg->trHeapMemory()) TR::J9S390InterfaceCallDataSnippet(cg,c,n,thunkPtr);
835
cg->addDataConstantSnippet(_dataSnippet);
836
}
837
838
uint8_t *
839
TR::S390InterfaceCallSnippet::emitSnippetBody()
840
{
841
uint8_t * cursor = cg()->getBinaryBufferCursor();
842
getSnippetLabel()->setCodeLocation(cursor);
843
TR::Compilation *comp = cg()->comp();
844
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());
845
846
uint32_t rEP = (uint32_t) cg()->getEntryPointRegister() - 1;
847
TR::SymbolReference * glueRef ;
848
849
if (getNumInterfaceCallCacheSlots() == 0)
850
{
851
glueRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_S390interfaceCallHelper);
852
}
853
else if (comp->getOption(TR_enableInterfaceCallCachingSingleDynamicSlot))
854
{
855
glueRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_S390interfaceCallHelperSingleDynamicSlot);
856
}
857
else
858
{
859
glueRef = cg()->symRefTab()->findOrCreateRuntimeHelper(TR_S390interfaceCallHelperMultiSlots);
860
}
861
862
// Set up the start of data constants and jump to helper.
863
// LARL r14, <Start of DC>
864
// BRCL <Helper Addr>
865
866
// LARL - Add Relocation the data constants to this LARL.
867
cg()->addRelocation(new (cg()->trHeapMemory()) TR::LabelRelative32BitRelocation(cursor, getDataConstantSnippet()->getSnippetLabel()));
868
869
*(int16_t *) cursor = 0xC0E0;
870
cursor += sizeof(int16_t);
871
872
// Place holder. Proper offset will be calculated by relocation.
873
*(int32_t *) cursor = 0xDEADBEEF;
874
cursor += sizeof(int32_t);
875
876
// BRCL
877
*(int16_t *) cursor = 0xC0F4;
878
cursor += sizeof(int16_t);
879
880
// Calculate the relative offset to get to helper method.
881
// If MCC is not supported, everything should be reachable.
882
// If MCC is supported, we will look up the appropriate trampoline, if
883
// necessary.
884
intptr_t destAddr = (intptr_t)(glueRef->getMethodAddress());
885
886
#if defined(TR_TARGET_64BIT)
887
#if defined(J9ZOS390)
888
if (comp->getOption(TR_EnableRMODE64))
889
#endif
890
{
891
if (NEEDS_TRAMPOLINE(destAddr, cursor, cg()))
892
{
893
// Destination is beyond our reachable jump distance, we'll find the
894
// trampoline.
895
destAddr = TR::CodeCacheManager::instance()->findHelperTrampoline(glueRef->getReferenceNumber(), (void *)cursor);
896
this->setUsedTrampoline(true);
897
}
898
}
899
#endif
900
901
TR_ASSERT(CHECK_32BIT_TRAMPOLINE_RANGE(destAddr, cursor), "Helper Call is not reachable.");
902
this->setSnippetDestAddr(destAddr);
903
904
*(int32_t *) cursor = (int32_t)((destAddr - (intptr_t)(cursor - 2)) / 2);
905
AOTcgDiag1(comp, " add TR_HelperAddress cursor=%x\n", cursor);
906
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, (uint8_t*) glueRef, TR_HelperAddress, cg()),
907
__FILE__, __LINE__, getNode());
908
cursor += sizeof(int32_t);
909
910
// Set up the code RA to the data snippet.
911
getDataConstantSnippet()->setCodeRA(getCallRA());
912
913
return cursor;
914
}
915
916
uint32_t
917
TR::S390InterfaceCallSnippet::getLength(int32_t estimatedSnippetStart)
918
{
919
return 12; // LARL + BRCL
920
}
921
922
923
924
void
925
TR_Debug::print(TR::FILE *pOutFile, TR::S390UnresolvedCallSnippet * snippet)
926
{
927
uint8_t * bufferPos = snippet->getSnippetLabel()->getCodeLocation() + snippet->getLength(0)
928
- sizeof(intptr_t) - sizeof(int32_t) // 2 DC's at end of this snippet.
929
- (sizeof(intptr_t) - snippet->getPadBytes()); // padding
930
931
TR::SymbolReference * methodSymRef = snippet->getNode()->getSymbolReference();
932
933
int32_t helperLookupOffset;
934
switch (snippet->getNode()->getDataType())
935
{
936
case TR::NoType:
937
helperLookupOffset = 0;
938
break;
939
case TR::Int32:
940
case TR::Address:
941
helperLookupOffset = 4;
942
break;
943
case TR::Int64:
944
helperLookupOffset = 8;
945
break;
946
case TR::Float:
947
helperLookupOffset = 12;
948
break;
949
case TR::Double:
950
helperLookupOffset = 16;
951
break;
952
}
953
helperLookupOffset <<= 24;
954
955
snippet->print(pOutFile, this);
956
957
printPrefix(pOutFile, NULL, bufferPos, sizeof(uintptr_t));
958
trfprintf(pOutFile, "DC \t%p \t\t# Address Of Constant Pool", getOwningMethod(methodSymRef)->constantPool());
959
bufferPos += sizeof(uintptr_t);
960
961
printPrefix(pOutFile, NULL, bufferPos, 4);
962
trfprintf(pOutFile, "DC \t0x%08x \t\t# Offset | Flag | CP Index", helperLookupOffset | methodSymRef->getCPIndexForVM());
963
}
964
965
966
void
967
TR_Debug::print(TR::FILE *pOutFile, TR::S390VirtualSnippet * snippet)
968
{
969
uint8_t * bufferPos = snippet->getSnippetLabel()->getCodeLocation();
970
printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, "Virtual Call Snippet");
971
}
972
973
974
void
975
TR_Debug::print(TR::FILE *pOutFile, TR::S390VirtualUnresolvedSnippet * snippet)
976
{
977
uint8_t * bufferPos = snippet->getSnippetLabel()->getCodeLocation();
978
TR::SymbolReference * methodSymRef = snippet->getNode()->getSymbolReference();
979
TR::SymbolReference * glueRef = _cg->getSymRef(TR_S390virtualUnresolvedHelper);
980
981
printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, "Virtual Unresolved Call Snippet");
982
983
bufferPos = printRuntimeInstrumentationOnOffInstruction(pOutFile, bufferPos, false); // RIOFF
984
985
printPrefix(pOutFile, NULL, bufferPos, 6);
986
trfprintf(pOutFile, "BRASL \tGPR14, <%p>\t# Branch to Helper Method %s",
987
snippet->getSnippetDestAddr(),
988
snippet->usedTrampoline()?"- Trampoline Used.":"");
989
bufferPos += 6;
990
991
printPrefix(pOutFile, NULL, bufferPos, 4);
992
trfprintf(pOutFile, "DC \t%p\t\t# Method Address", *((uintptr_t *)bufferPos));
993
bufferPos += sizeof(intptr_t);
994
995
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
996
trfprintf(pOutFile, "DC \t%p \t\t# Call Site RA", snippet->getCallRA());
997
bufferPos += sizeof(intptr_t);
998
999
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1000
trfprintf(pOutFile, "DC \t%p \t\t# Address Of Constant Pool", (intptr_t) getOwningMethod(methodSymRef)->constantPool());
1001
bufferPos += sizeof(intptr_t);
1002
1003
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1004
trfprintf(pOutFile, "DC \t0x%08x \t\t# CP Index", methodSymRef->getCPIndexForVM());
1005
bufferPos += sizeof(intptr_t);
1006
1007
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1008
trfprintf(pOutFile, "DC \t%p \t\t# Instruction to be patched with vft offset", snippet->getPatchVftInstruction()->getBinaryEncoding());
1009
bufferPos += sizeof(intptr_t);
1010
1011
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1012
trfprintf(pOutFile, "DC \t%p \t\t# Private J9Method pointer", 0);
1013
bufferPos += sizeof(intptr_t);
1014
1015
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1016
trfprintf(pOutFile, "DC \t%p \t\t# J2I thunk address for private", snippet->getJ2IThunkAddress());
1017
bufferPos += sizeof(intptr_t);
1018
1019
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1020
trfprintf(pOutFile, "DC \t%p \t\t# RA for private", snippet->getBranchInstruction()->getBinaryEncoding() + snippet->getIndirectCallInstruction()->getBinaryLength());
1021
}
1022
1023
1024
void
1025
TR_Debug::print(TR::FILE *pOutFile, TR::S390InterfaceCallSnippet * snippet)
1026
{
1027
uint8_t * bufferPos = snippet->getSnippetLabel()->getCodeLocation();
1028
TR::SymbolReference * methodSymRef = snippet->getNode()->getSymbolReference();
1029
TR::SymbolReference * glueRef = _cg->getSymRef(TR_S390interfaceCallHelperMultiSlots);
1030
int i;
1031
1032
printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, "Interface Call Snippet");
1033
1034
printPrefix(pOutFile, NULL, bufferPos, 6);
1035
trfprintf(pOutFile, "LARL \tGPR14, <%p>\t# Addr of DataConst",
1036
(intptr_t) snippet->getDataConstantSnippet()->getSnippetLabel()->getCodeLocation());
1037
bufferPos += 6;
1038
1039
printPrefix(pOutFile, NULL, bufferPos, 6);
1040
trfprintf(pOutFile, "BRCL \t<%p>\t\t# Branch to Helper %s",
1041
snippet->getSnippetDestAddr(),
1042
snippet->usedTrampoline()?"- Trampoline Used.":"");
1043
bufferPos += 6;
1044
}
1045
1046
void
1047
TR_Debug::print(TR::FILE *pOutFile, TR::J9S390InterfaceCallDataSnippet * snippet)
1048
{
1049
uint8_t * bufferPos = snippet->getSnippetLabel()->getCodeLocation();
1050
1051
// This follows the snippet format in TR::J9S390InterfaceCallDataSnippet::emitSnippetBody
1052
uint8_t refSize = TR::Compiler->om.sizeofReferenceAddress();
1053
1054
printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, "Interface call cache data snippet");
1055
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1056
trfprintf(pOutFile, "DC \t0x%016lx # Call site RA", *(intptr_t*)bufferPos);
1057
bufferPos += refSize;
1058
1059
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1060
trfprintf(pOutFile, "DC \t0x%016lx # Address of constant pool", *(intptr_t*)bufferPos);
1061
bufferPos += refSize;
1062
1063
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1064
trfprintf(pOutFile, "DC \t0x%016lx # CP index", *(intptr_t*)bufferPos);
1065
bufferPos += refSize;
1066
1067
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1068
trfprintf(pOutFile, "DC \t0x%016lx # Interface class", *(intptr_t*)bufferPos);
1069
bufferPos += refSize;
1070
1071
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1072
trfprintf(pOutFile, "DC \t0x%016lx # Method index", *(intptr_t*)bufferPos);
1073
bufferPos += refSize;
1074
1075
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1076
trfprintf(pOutFile, "DC \t0x%016lx # J2I thunk address ", *(intptr_t*)bufferPos);
1077
bufferPos += refSize;
1078
1079
// zero cache slot
1080
if (snippet->getNumInterfaceCallCacheSlots() == 0)
1081
{
1082
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1083
trfprintf(pOutFile, "DC \t0x%016lx # flags", *(intptr_t*)bufferPos);
1084
bufferPos += refSize;
1085
}
1086
1087
// non-single cache slots
1088
bool isSingleDynamicSlot = comp()->getOption(TR_enableInterfaceCallCachingSingleDynamicSlot);
1089
if (!isSingleDynamicSlot)
1090
{
1091
// flags
1092
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1093
trfprintf(pOutFile, "DC \t0x%016lx # flags", *(intptr_t*)bufferPos);
1094
bufferPos += refSize;
1095
1096
// lastCachedSlot
1097
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1098
trfprintf(pOutFile, "DC \t0x%016lx # last cached slot", *(intptr_t*)bufferPos);
1099
bufferPos += refSize;
1100
1101
// firstSlot
1102
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1103
trfprintf(pOutFile, "DC \t0x%016lx # first slot", *(intptr_t*)bufferPos);
1104
bufferPos += refSize;
1105
1106
// lastSlot
1107
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1108
trfprintf(pOutFile, "DC \t0x%016lx # last slot", *(intptr_t*)bufferPos);
1109
bufferPos += refSize;
1110
}
1111
1112
// print profiled class list
1113
int32_t numInterfaceCallCacheSlots = snippet->getNumInterfaceCallCacheSlots();
1114
bool isUseCLFIandBRCL = snippet->isUseCLFIandBRCL();
1115
TR::list<TR_OpaqueClassBlock*> * profiledClassesList = comp()->cg()->getPICsListForInterfaceSnippet(snippet);
1116
1117
if (profiledClassesList)
1118
{
1119
for (auto iter = profiledClassesList->begin(); iter != profiledClassesList->end(); ++iter)
1120
{
1121
numInterfaceCallCacheSlots--;
1122
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1123
trfprintf(pOutFile, "DC \t0x%016lx # profiled class", *(intptr_t*)bufferPos);
1124
bufferPos += refSize;
1125
1126
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1127
trfprintf(pOutFile, "DC \t0x%016lx # profiled method", *(intptr_t*)bufferPos);
1128
bufferPos += refSize;
1129
}
1130
}
1131
1132
// print remaining class list
1133
for (uint32_t i = 0; i < numInterfaceCallCacheSlots; i++)
1134
{
1135
if (isUseCLFIandBRCL)
1136
{
1137
// address of CLFI's immediate field
1138
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1139
trfprintf(pOutFile, "DC \t0x%016lx # address of CLFI's immediate field", *(intptr_t*)bufferPos);
1140
bufferPos += refSize;
1141
}
1142
else
1143
{
1144
// class pointer
1145
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1146
trfprintf(pOutFile, "DC \t0x%016lx # class pointer %d", *(intptr_t*)bufferPos, i);
1147
bufferPos += refSize;
1148
1149
// method pointer
1150
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1151
trfprintf(pOutFile, "DC \t0x%016lx # method pointer %d", *(intptr_t*)bufferPos, i);
1152
bufferPos += refSize;
1153
}
1154
}
1155
1156
if (isSingleDynamicSlot)
1157
{
1158
// flags
1159
printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1160
trfprintf(pOutFile, "DC \t0x%016lx # method pointer", *(intptr_t*)bufferPos);
1161
bufferPos += refSize;
1162
}
1163
return;
1164
}
1165
1166
///////////////////////////////////////////////////////////////////////////////
1167
// TR::J9S390InterfaceCallDataSnippet member functions
1168
///////////////////////////////////////////////////////////////////////////////
1169
TR::J9S390InterfaceCallDataSnippet::J9S390InterfaceCallDataSnippet(TR::CodeGenerator * cg,
1170
TR::Node * node,
1171
uint8_t n,
1172
void *thunkPtr,
1173
bool useCLFIandBRCL)
1174
: TR::S390ConstantDataSnippet(cg,node,generateLabelSymbol(cg),0),
1175
_numInterfaceCallCacheSlots(n),
1176
_codeRA(NULL),
1177
_thunkAddress(thunkPtr),
1178
_useCLFIandBRCL(useCLFIandBRCL)
1179
{
1180
}
1181
1182
/**
1183
* \brief
1184
* Emits interface call data snippet, which can take three layouts: 0-slot, single-dynamic-slot, and 4-slot layouts.
1185
* The default layout has 4-slots.
1186
*/
1187
uint8_t *
1188
TR::J9S390InterfaceCallDataSnippet::emitSnippetBody()
1189
{
1190
1191
/*
1192
* 4-slot Layout (example showing 64-bit fields). 4-slot is the default case.
1193
*
1194
* Note: some fields and PIC slots will be unused if interface call turns out to be a direct dispatch.
1195
*
1196
* Snippet Label L0049: ; Interface call cache data snippet
1197
* DC 0x0000000084e00244 # Call site RA
1198
* DC 0x0000000000202990 # Address of constant pool
1199
* DC 0x0000000000000008 # CP index
1200
* DC 0x0000000000000000 # Interface class (vm helper will fill it up with call resolution class info)
1201
* DC 0x0000000000000000 # Method index (vm helper will fill it up with call resolution method info. This contains
1202
* J9method if it's direct dispatch. It's I-table offset if it's a normal interface call)
1203
* DC 0x0000000084ffd408 # J2I thunk (J2I thunk address)
1204
* DC 0x0000000000000000 # flags (this 64-bit number is initially 0, meaning the call is unresolved. It'll be 1 once resolved)
1205
* DC 0x0000000084e00408 # last cached slot
1206
* DC 0x0000000084e00418 # first slot (address of class pointer 0)
1207
* DC 0x0000000084e00448 # last slot (address of class pointer 3)
1208
* DC 0x0000000000000000 # class pointer 0 (8 or 16 byte aligned PIC slots. all PICs starting from this point are
1209
* un-used if the call is resolved as private, which is direct dispatch)
1210
* DC 0x0000000000000000 # method pointer 0
1211
* DC 0x0000000000000000 # class pointer 1
1212
* DC 0x0000000000000000 # method pointer 1
1213
* DC 0x0000000000000000 # class pointer 2
1214
* DC 0x0000000000000000 # method pointer 2
1215
* DC 0x0000000000000000 # class pointer 3
1216
* DC 0x0000000000000000 # method pointer 3
1217
*
1218
* If we use CLFI / BRCL
1219
* DC 0x0000000000000000 ; Patch slot of the first CLFI (Class 1)
1220
* DC 0x0000000000000000 ; Patch slot of the second CLFI (Class 2)
1221
* DC 0x0000000000000000 ; Patch slot of the third CLFI (Class 3)
1222
* and so on ...
1223
*
1224
*
1225
* Single dynamic slot layout
1226
*
1227
* Snippet Label L0049: ; Interface call cache data snippet
1228
* DC 0x00000000529941ca # Call site RA
1229
* DC 0x0000000000202990 # Address of constant pool
1230
* DC 0x0000000000000008 # CP index
1231
* DC 0x0000000000000000 # Interface class
1232
* DC 0x0000000000000000 # Method index
1233
* DC 0x0000000052b91408 # J2I thunk
1234
* DC 0x0000000000000000 # class pointer 0
1235
* DC 0x0000000000000000 # method pointer 0
1236
* DC 0x0000000000000000 # flags
1237
*
1238
*
1239
* 0-slot example
1240
*
1241
* Snippet Label L0041: ; Interface call cache data snippet
1242
* DC 0x0000000065a7f156 # Call site RA
1243
* DC 0x0000000000202990 # Address of constant pool
1244
* DC 0x000000000000000e # CP index
1245
* DC 0x0000000000000000 # Interface class
1246
* DC 0x0000000000000000 # Method index
1247
* DC 0x0000000065c7c408 # Interpreter thunk
1248
* DC 0x0000000000000000 # flags
1249
*/
1250
TR::Compilation *comp = cg()->comp();
1251
int32_t i = 0;
1252
uint8_t * cursor = cg()->getBinaryBufferCursor();
1253
AOTcgDiag1(comp, "TR::S390InterfaceCallDataSnippet::emitSnippetBody cursor=%x\n", cursor);
1254
1255
// Class Pointer must be double word aligned.
1256
// For 64-bit single dynamic slot, LPQ and STPQ instructions will be emitted; and they require quadword alignment
1257
int32_t alignment = comp->getOption(TR_enableInterfaceCallCachingSingleDynamicSlot) ? 16 : 8;
1258
intptr_t startOfPIC = (intptr_t)cursor + 6 * sizeof(intptr_t);
1259
int32_t padSize = 0;
1260
1261
if ((startOfPIC % alignment) != 0)
1262
{
1263
padSize = (alignment - (startOfPIC % alignment));
1264
}
1265
1266
cursor += padSize;
1267
1268
getSnippetLabel()->setCodeLocation(cursor);
1269
TR::Node * callNode = getNode();
1270
1271
1272
intptr_t snippetStart = (intptr_t)cursor;
1273
1274
// code cache RA
1275
TR_ASSERT_FATAL(_codeRA != NULL, "Interface Call Data Constant's code return address not initialized.\n");
1276
*(uintptr_t *) cursor = (uintptr_t)_codeRA;
1277
AOTcgDiag1(comp, "add TR_AbsoluteMethodAddress cursor=%x\n", cursor);
1278
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, NULL, TR_AbsoluteMethodAddress, cg()),
1279
__FILE__, __LINE__, callNode);
1280
1281
cursor += TR::Compiler->om.sizeofReferenceAddress();
1282
1283
// constant pool
1284
*(uintptr_t *) cursor = (uintptr_t) callNode->getSymbolReference()->getOwningMethod(comp)->constantPool();
1285
1286
// J2I relocation information for private nestmate calls
1287
auto j2iRelocInfo = reinterpret_cast<TR_RelocationRecordInformation*>(comp->trMemory()->allocateMemory(sizeof(TR_RelocationRecordInformation), heapAlloc));
1288
j2iRelocInfo->data1 = *(uintptr_t *) cursor; // CP address
1289
j2iRelocInfo->data2 = (uintptr_t)(callNode ? callNode->getInlinedSiteIndex() : -1); // inlined site index
1290
uintptr_t cpAddrPosition = (uintptr_t)cursor; // for data3 calculation
1291
1292
cursor += TR::Compiler->om.sizeofReferenceAddress();
1293
1294
// save CPIndex as sign extended 8 byte value on 64bit as it's assumed in J9 helpers
1295
// cp index
1296
*(intptr_t *) cursor = (intptr_t) callNode->getSymbolReference()->getCPIndex();
1297
cursor += TR::Compiler->om.sizeofReferenceAddress();
1298
1299
//interface class
1300
*(uintptr_t *) cursor = 0;
1301
cursor += TR::Compiler->om.sizeofReferenceAddress();
1302
1303
// method index
1304
*(intptr_t *) cursor = 0;
1305
cursor += TR::Compiler->om.sizeofReferenceAddress();
1306
1307
// J2I thunk address.
1308
// Note that J2I thunk relocation is associated with CP addr and the call to `addExternalRelocation` uses CP-Addr cursor.
1309
*(intptr_t *) cursor = (intptr_t)_thunkAddress;
1310
j2iRelocInfo->data3 = (uintptr_t)cursor - cpAddrPosition; // data3 is the offset of CP_addr to J2I thunk
1311
1312
AOTcgDiag1(comp, "add TR_J2IVirtualThunkPointer cursor=%x\n", cursor);
1313
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation((uint8_t*)cpAddrPosition, (uint8_t*)j2iRelocInfo, NULL,
1314
TR_J2IVirtualThunkPointer, cg()),
1315
__FILE__, __LINE__, callNode);
1316
1317
cursor += TR::Compiler->om.sizeofReferenceAddress();
1318
1319
if (getNumInterfaceCallCacheSlots() == 0)
1320
{
1321
// Flags
1322
*(intptr_t *) (cursor) = 0;
1323
cursor += TR::Compiler->om.sizeofReferenceAddress();
1324
return cursor;
1325
}
1326
uint8_t * cursorlastCachedSlot = 0;
1327
bool isSingleDynamic = comp->getOption(TR_enableInterfaceCallCachingSingleDynamicSlot);
1328
1329
if (!isSingleDynamic)
1330
{
1331
// Flags
1332
*(intptr_t *) (cursor) = 0;
1333
cursor += TR::Compiler->om.sizeofReferenceAddress();
1334
1335
// lastCachedSlot
1336
cursorlastCachedSlot = cursor;
1337
*(intptr_t *) (cursor) = snippetStart + getFirstSlotOffset() - (2 * TR::Compiler->om.sizeofReferenceAddress());
1338
AOTcgDiag1(comp, "add TR_AbsoluteMethodAddress cursor=%x\n", cursor);
1339
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, NULL, TR_AbsoluteMethodAddress, cg()),
1340
__FILE__, __LINE__, callNode);
1341
1342
cursor += TR::Compiler->om.sizeofReferenceAddress();
1343
1344
// firstSlot
1345
*(intptr_t *) (cursor) = snippetStart + getFirstSlotOffset();
1346
AOTcgDiag1(comp, "add TR_AbsoluteMethodAddress cursor=%x\n", cursor);
1347
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, NULL, TR_AbsoluteMethodAddress, cg()),
1348
__FILE__, __LINE__, callNode);
1349
cursor += TR::Compiler->om.sizeofReferenceAddress();
1350
1351
// lastSlot
1352
*(intptr_t *) (cursor) = snippetStart + getLastSlotOffset();
1353
AOTcgDiag1(comp, "add TR_AbsoluteMethodAddress cursor=%x\n", cursor);
1354
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, NULL, TR_AbsoluteMethodAddress, cg()),
1355
__FILE__, __LINE__, callNode);
1356
cursor += TR::Compiler->om.sizeofReferenceAddress();
1357
}
1358
1359
// Cursor must be double word aligned by this point
1360
// so that 64-bit single dynamic slot can use LPQ to concurrently load a quadword.
1361
TR_ASSERT_FATAL( (!isSingleDynamic && (intptr_t)cursor % 8 == 0)
1362
|| (comp->target().is64Bit() && isSingleDynamic && (intptr_t)cursor % 16 == 0),
1363
"Interface Call Data Snippet Class Ptr is not double word aligned.");
1364
1365
bool updateField = false;
1366
int32_t numInterfaceCallCacheSlots = getNumInterfaceCallCacheSlots();
1367
TR::list<TR_OpaqueClassBlock*> * profiledClassesList = cg()->getPICsListForInterfaceSnippet(this);
1368
if (profiledClassesList)
1369
{
1370
for (auto valuesIt = profiledClassesList->begin(); valuesIt != profiledClassesList->end(); ++valuesIt)
1371
{
1372
TR::SymbolReference *methodSymRef = callNode->getSymbolReference();
1373
TR_ResolvedMethod * profiledMethod = methodSymRef->getOwningMethod(comp)->getResolvedInterfaceMethod(comp,
1374
(TR_OpaqueClassBlock *)(*valuesIt), methodSymRef->getCPIndex());
1375
numInterfaceCallCacheSlots--;
1376
updateField = true;
1377
if (comp->target().is64Bit() && TR::Compiler->om.generateCompressedObjectHeaders())
1378
*(uintptr_t *) cursor = (uintptr_t) (*valuesIt) << 32;
1379
else
1380
*(uintptr_t *) cursor = (uintptr_t) (*valuesIt);
1381
1382
if (comp->getOption(TR_EnableHCR))
1383
{
1384
cg()->jitAddPicToPatchOnClassRedefinition(*valuesIt, (void *) cursor);
1385
}
1386
1387
if (cg()->fe()->isUnloadAssumptionRequired((TR_OpaqueClassBlock *)(*valuesIt), comp->getCurrentMethod()))
1388
{
1389
cg()->jitAddPicToPatchOnClassUnload(*valuesIt, (void *) cursor);
1390
}
1391
1392
cursor += TR::Compiler->om.sizeofReferenceAddress();
1393
1394
// Method Pointer
1395
*(uintptr_t *) (cursor) = (uintptr_t)profiledMethod->startAddressForJittedMethod();
1396
cursor += TR::Compiler->om.sizeofReferenceAddress();
1397
}
1398
1399
}
1400
1401
// Skip the top cache slots that are filled with IProfiler data by setting the cursorlastCachedSlot to point to the fist dynamic cache slot
1402
if (updateField)
1403
{
1404
*(intptr_t *) (cursorlastCachedSlot) = snippetStart + getFirstSlotOffset() + ((getNumInterfaceCallCacheSlots()-numInterfaceCallCacheSlots-1)*2 * TR::Compiler->om.sizeofReferenceAddress());
1405
}
1406
1407
for (i = 0; i < numInterfaceCallCacheSlots; i++)
1408
{
1409
if (isUseCLFIandBRCL())
1410
{
1411
// Get Address of CLFI's immediate field (2 bytes into CLFI instruction).
1412
// jitAddPicToPatchOnClassUnload is called by PicBuilder code when the cache is populated.
1413
*(intptr_t*) cursor = (intptr_t)(getFirstCLFI()->getBinaryEncoding() ) + (intptr_t)(i * 12 + 2);
1414
cursor += TR::Compiler->om.sizeofReferenceAddress();
1415
}
1416
else
1417
{
1418
// Class Pointer - jitAddPicToPatchOnClassUnload is called by PicBuilder code when the cache is populated.
1419
*(intptr_t *) cursor = 0;
1420
cursor += TR::Compiler->om.sizeofReferenceAddress();
1421
1422
// Method Pointer
1423
*(intptr_t *) (cursor) = 0;
1424
cursor += TR::Compiler->om.sizeofReferenceAddress();
1425
}
1426
}
1427
1428
if (isSingleDynamic)
1429
{
1430
// Flags
1431
*(intptr_t *) (cursor) = 0;
1432
cursor += TR::Compiler->om.sizeofReferenceAddress();
1433
}
1434
1435
return cursor;
1436
}
1437
1438
1439
uint32_t
1440
TR::J9S390InterfaceCallDataSnippet::getCallReturnAddressOffset()
1441
{
1442
return 0;
1443
}
1444
1445
uint32_t
1446
TR::J9S390InterfaceCallDataSnippet::getSingleDynamicSlotOffset()
1447
{
1448
return getCallReturnAddressOffset() + 6 * TR::Compiler->om.sizeofReferenceAddress();
1449
}
1450
1451
uint32_t
1452
TR::J9S390InterfaceCallDataSnippet::getLastCachedSlotFieldOffset()
1453
{
1454
return getCallReturnAddressOffset() + 7 * TR::Compiler->om.sizeofReferenceAddress();
1455
}
1456
1457
uint32_t
1458
TR::J9S390InterfaceCallDataSnippet::getFirstSlotFieldOffset()
1459
{
1460
return getLastCachedSlotFieldOffset() + TR::Compiler->om.sizeofReferenceAddress();
1461
}
1462
1463
uint32_t
1464
TR::J9S390InterfaceCallDataSnippet::getLastSlotFieldOffset()
1465
{
1466
return getFirstSlotFieldOffset() + TR::Compiler->om.sizeofReferenceAddress();
1467
}
1468
1469
uint32_t
1470
TR::J9S390InterfaceCallDataSnippet::getFirstSlotOffset()
1471
{
1472
return getLastSlotFieldOffset() + TR::Compiler->om.sizeofReferenceAddress();
1473
}
1474
1475
uint32_t
1476
TR::J9S390InterfaceCallDataSnippet::getLastSlotOffset()
1477
{
1478
return (getFirstSlotOffset() +
1479
(getNumInterfaceCallCacheSlots() - 1) *
1480
((isUseCLFIandBRCL()?1:2) * TR::Compiler->om.sizeofReferenceAddress()));
1481
}
1482
1483
uint32_t
1484
TR::J9S390InterfaceCallDataSnippet::getLength(int32_t)
1485
{
1486
TR::Compilation *comp = cg()->comp();
1487
// the 1st item is for padding...
1488
if (getNumInterfaceCallCacheSlots()== 0)
1489
return 3 * TR::Compiler->om.sizeofReferenceAddress() + 8 * TR::Compiler->om.sizeofReferenceAddress();
1490
1491
if (comp->getOption(TR_enableInterfaceCallCachingSingleDynamicSlot))
1492
return 3 * TR::Compiler->om.sizeofReferenceAddress() + getSingleDynamicSlotOffset() + 4 * TR::Compiler->om.sizeofReferenceAddress();
1493
1494
if (getNumInterfaceCallCacheSlots() > 0)
1495
return 3 * TR::Compiler->om.sizeofReferenceAddress() + getLastSlotOffset() + TR::Compiler->om.sizeofReferenceAddress();
1496
1497
TR_ASSERT(0,"Interface Call Data Snippet has 0 size.");
1498
return 0;
1499
}
1500
1501
1502
uint32_t
1503
TR::S390JNICallDataSnippet::getJNICallOutFrameFlagsOffset()
1504
{
1505
return TR::Compiler->om.sizeofReferenceAddress();
1506
}
1507
1508
uint32_t
1509
TR::S390JNICallDataSnippet::getReturnFromJNICallOffset()
1510
{
1511
return 2 * TR::Compiler->om.sizeofReferenceAddress();
1512
}
1513
1514
uint32_t
1515
TR::S390JNICallDataSnippet::getSavedPCOffset()
1516
{
1517
return 3 * TR::Compiler->om.sizeofReferenceAddress();
1518
}
1519
1520
uint32_t
1521
TR::S390JNICallDataSnippet::getTagBitsOffset()
1522
{
1523
return 4 * TR::Compiler->om.sizeofReferenceAddress();
1524
}
1525
1526
uint32_t
1527
TR::S390JNICallDataSnippet::getPCOffset()
1528
{
1529
return 5 * TR::Compiler->om.sizeofReferenceAddress();
1530
}
1531
1532
uint32_t
1533
TR::S390JNICallDataSnippet::getLiteralsOffset()
1534
{
1535
return 6 * TR::Compiler->om.sizeofReferenceAddress();
1536
}
1537
1538
uint32_t
1539
TR::S390JNICallDataSnippet::getJitStackFrameFlagsOffset()
1540
{
1541
return 7 * TR::Compiler->om.sizeofReferenceAddress();
1542
}
1543
1544
uint32_t
1545
TR::S390JNICallDataSnippet::getConstReleaseVMAccessMaskOffset()
1546
{
1547
return 8 * TR::Compiler->om.sizeofReferenceAddress();
1548
}
1549
1550
uint32_t
1551
TR::S390JNICallDataSnippet::getConstReleaseVMAccessOutOfLineMaskOffset()
1552
{
1553
return 9 * TR::Compiler->om.sizeofReferenceAddress();
1554
}
1555
1556
uint32_t
1557
TR::S390JNICallDataSnippet::getTargetAddressOffset()
1558
{
1559
return 10 * TR::Compiler->om.sizeofReferenceAddress();
1560
}
1561
1562
uint32_t
1563
TR::S390JNICallDataSnippet::getLength(int32_t estimatedSnippetStart)
1564
{
1565
return 12 * TR::Compiler->om.sizeofReferenceAddress(); /*one ptr more for possible padding */
1566
}
1567
1568
1569
TR::S390JNICallDataSnippet::S390JNICallDataSnippet(TR::CodeGenerator * cg,
1570
TR::Node * node)
1571
: TR::S390ConstantDataSnippet(cg, node, generateLabelSymbol(cg),0),
1572
_baseRegister(0),
1573
_ramMethod(0),
1574
_JNICallOutFrameFlags(0),
1575
_returnFromJNICallLabel(0),
1576
_savedPC(0),
1577
_tagBits(0),
1578
_pc(0),
1579
_literals(0),
1580
_jitStackFrameFlags(0),
1581
_constReleaseVMAccessMask(0),
1582
_constReleaseVMAccessOutOfLineMask(0),
1583
_targetAddress(0)
1584
{
1585
return;
1586
}
1587
1588
uint8_t *
1589
TR::S390JNICallDataSnippet::emitSnippetBody()
1590
{
1591
uint8_t * cursor = cg()->getBinaryBufferCursor();
1592
1593
/* TR::S390JNICallDataSnippet Layout: all fields are pointer sized
1594
ramMethod
1595
JNICallOutFrameFlags
1596
returnFromJNICall
1597
savedPC
1598
tagBits
1599
pc
1600
literals
1601
jitStackFrameFlags
1602
constReleaseVMAccessMask
1603
constReleaseVMAccessOutOfLineMask
1604
targetAddress
1605
*/
1606
TR::Compilation *comp = cg()->comp();
1607
1608
AOTcgDiag1(comp, "TR::S390JNICallDataSnippet::emitSnippetBody cursor=%x\n", cursor);
1609
// Ensure pointer sized alignment
1610
int32_t alignSize = TR::Compiler->om.sizeofReferenceAddress();
1611
int32_t padBytes = ((intptr_t)cursor + alignSize -1) / alignSize * alignSize - (intptr_t)cursor;
1612
cursor += padBytes;
1613
1614
getSnippetLabel()->setCodeLocation(cursor);
1615
TR::Node * callNode = getNode();
1616
1617
intptr_t snippetStart = (intptr_t)cursor;
1618
1619
// JNI Callout Frame data
1620
// _ramMethod
1621
*(intptr_t *) cursor = (intptr_t) _ramMethod;
1622
1623
TR_ExternalRelocationTargetKind reloType;
1624
if (getNode()->getSymbol()->castToResolvedMethodSymbol()->isSpecial())
1625
reloType = TR_SpecialRamMethodConst;
1626
else if (getNode()->getSymbol()->castToResolvedMethodSymbol()->isStatic())
1627
reloType = TR_StaticRamMethodConst;
1628
else if (getNode()->getSymbol()->castToResolvedMethodSymbol()->isVirtual())
1629
reloType = TR_VirtualRamMethodConst;
1630
else
1631
{
1632
reloType = TR_NoRelocation;
1633
TR_ASSERT(0,"JNI relocation not supported.");
1634
}
1635
1636
AOTcgDiag2(comp, "add relocation (%d) cursor=%x\n", reloType, cursor);
1637
if (cg()->needClassAndMethodPointerRelocations())
1638
{
1639
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, (uint8_t *) callNode->getSymbolReference(),
1640
callNode ? (uint8_t *)(intptr_t)callNode->getInlinedSiteIndex() : (uint8_t *)-1,
1641
reloType, cg()),
1642
__FILE__, __LINE__, callNode);
1643
}
1644
1645
cursor += TR::Compiler->om.sizeofReferenceAddress();
1646
1647
// _JNICallOutFrameFlags
1648
*(intptr_t *) cursor = (intptr_t) _JNICallOutFrameFlags;
1649
cursor += TR::Compiler->om.sizeofReferenceAddress();
1650
// _returnFromJNICall
1651
*(intptr_t *) cursor = (intptr_t) (_returnFromJNICallLabel->getCodeLocation());
1652
1653
AOTcgDiag1(comp, "add TR_AbsoluteMethodAddress cursor=%x\n", cursor);
1654
cg()->addRelocation(new (cg()->trHeapMemory()) TR::LabelAbsoluteRelocation(cursor, _returnFromJNICallLabel));
1655
cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(cursor, NULL, TR_AbsoluteMethodAddress, cg()),
1656
__FILE__, __LINE__, getNode());
1657
1658
cursor += TR::Compiler->om.sizeofReferenceAddress();
1659
// _savedPC
1660
*(intptr_t *) cursor = (intptr_t) _savedPC;
1661
cursor += TR::Compiler->om.sizeofReferenceAddress();
1662
// _tagBits
1663
*(intptr_t *) cursor = (intptr_t) _tagBits;
1664
cursor += TR::Compiler->om.sizeofReferenceAddress();
1665
1666
//VMThread data
1667
// _pc
1668
*(intptr_t *) cursor = (intptr_t) _pc;
1669
cursor += TR::Compiler->om.sizeofReferenceAddress();
1670
// _literals
1671
*(intptr_t *) cursor = (intptr_t) _literals;
1672
cursor += TR::Compiler->om.sizeofReferenceAddress();
1673
// _jitStackFrameFlags
1674
*(intptr_t *) cursor = (intptr_t) _jitStackFrameFlags;
1675
cursor += TR::Compiler->om.sizeofReferenceAddress();
1676
1677
// _constReleaseVMAccessMask
1678
*(intptr_t *) cursor = (intptr_t) _constReleaseVMAccessMask;
1679
cursor += TR::Compiler->om.sizeofReferenceAddress();
1680
// _constReleaseVMAccessOutOfLineMask
1681
*(intptr_t *) cursor = (intptr_t) _constReleaseVMAccessOutOfLineMask;
1682
cursor += TR::Compiler->om.sizeofReferenceAddress();
1683
1684
// _targetAddress/function pointer of native method
1685
*(intptr_t *) cursor = (intptr_t) _targetAddress;
1686
TR_OpaqueMethodBlock *method = getNode()->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod()->getPersistentIdentifier();
1687
1688
#ifdef J9VM_OPT_JITSERVER
1689
if (comp->isOutOfProcessCompilation())
1690
{
1691
// For JITServer we need to build a list of assumptions that will be sent to client at end of compilation
1692
intptr_t offset = cursor - cg()->getBinaryBufferStart();
1693
SerializedRuntimeAssumption* sar = new (cg()->trHeapMemory()) SerializedRuntimeAssumption(RuntimeAssumptionOnRegisterNative, (uintptr_t)method, offset);
1694
comp->getSerializedRuntimeAssumptions().push_front(sar);
1695
}
1696
else
1697
#endif // J9VM_OPT_JITSERVER
1698
{
1699
TR_PatchJNICallSite::make(cg()->fe(), cg()->trPersistentMemory(), (uintptr_t) method, cursor, comp->getMetadataAssumptionList());
1700
}
1701
1702
if (getNode()->getSymbol()->castToResolvedMethodSymbol()->isSpecial())
1703
reloType = TR_JNISpecialTargetAddress;
1704
else if (getNode()->getSymbol()->castToResolvedMethodSymbol()->isStatic())
1705
reloType = TR_JNIStaticTargetAddress;
1706
else if (getNode()->getSymbol()->castToResolvedMethodSymbol()->isVirtual())
1707
reloType = TR_JNIVirtualTargetAddress;
1708
else
1709
{
1710
reloType = TR_NoRelocation;
1711
TR_ASSERT(0,"JNI relocation not supported.");
1712
}
1713
1714
if (cg()->needClassAndMethodPointerRelocations())
1715
{
1716
TR_RelocationRecordInformation *info = new (comp->trHeapMemory()) TR_RelocationRecordInformation();
1717
info->data1 = 0;
1718
info->data2 = reinterpret_cast<uintptr_t>(callNode->getSymbolReference());
1719
int16_t inlinedSiteIndex = callNode ? callNode->getInlinedSiteIndex() : -1;
1720
info->data3 = static_cast<uintptr_t>(inlinedSiteIndex);
1721
1722
cg()->addExternalRelocation(
1723
new (cg()->trHeapMemory()) TR::ExternalRelocation(
1724
cursor,
1725
reinterpret_cast<uint8_t *>(info),
1726
reloType,
1727
cg()),
1728
__FILE__, __LINE__, callNode);
1729
}
1730
1731
cursor += TR::Compiler->om.sizeofReferenceAddress();
1732
1733
return cursor;
1734
}
1735
1736
void
1737
TR::S390JNICallDataSnippet::print(TR::FILE *pOutFile, TR_Debug *debug)
1738
{
1739
/*
1740
ramMethod
1741
JNICallOutFrameFlags
1742
returnFromJNICall
1743
savedPC
1744
tagBits
1745
pc
1746
literals
1747
jitStackFrameFlags
1748
constReleaseVMAccessMask
1749
constReleaseVMAccessOutOfLineMask
1750
targetAddress
1751
1752
*/
1753
TR_FrontEnd *fe = cg()->comp()->fe();
1754
uint8_t * bufferPos = getSnippetLabel()->getCodeLocation();
1755
1756
int i = 0;
1757
1758
debug->printSnippetLabel(pOutFile, getSnippetLabel(), bufferPos, "JNI Call Data Snippet");
1759
1760
debug->printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1761
trfprintf(pOutFile, "DC \t%p \t\t# ramMethod",*((intptr_t*)bufferPos));
1762
bufferPos += sizeof(intptr_t);
1763
1764
debug->printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1765
trfprintf(pOutFile, "DC \t%p \t\t# JNICallOutFrameFlags",*((intptr_t*)bufferPos));
1766
bufferPos += sizeof(intptr_t);
1767
1768
debug->printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1769
trfprintf(pOutFile, "DC \t%p \t\t# returnFromJNICall", *((intptr_t*)bufferPos));
1770
bufferPos += sizeof(intptr_t);
1771
1772
debug->printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1773
trfprintf(pOutFile, "DC \t%p \t\t# savedPC", *((intptr_t*)bufferPos));
1774
bufferPos += sizeof(intptr_t);
1775
1776
debug->printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1777
trfprintf(pOutFile, "DC \t%p \t\t# tagBits", *((intptr_t*)bufferPos));
1778
bufferPos += sizeof(intptr_t);
1779
1780
debug->printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1781
trfprintf(pOutFile, "DC \t%p \t\t# pc", *((intptr_t*)bufferPos));
1782
bufferPos += sizeof(intptr_t);
1783
1784
debug->printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1785
trfprintf(pOutFile, "DC \t%p \t\t# literals", *((intptr_t*)bufferPos));
1786
bufferPos += sizeof(intptr_t);
1787
1788
debug->printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1789
trfprintf(pOutFile, "DC \t%p \t\t# jitStackFrameFlags", *((intptr_t*)bufferPos));
1790
bufferPos += sizeof(intptr_t);
1791
1792
debug->printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1793
trfprintf(pOutFile, "DC \t%p \t\t# constReleaseVMAccessMask",*((intptr_t*)bufferPos));
1794
bufferPos += sizeof(intptr_t);
1795
1796
debug->printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1797
trfprintf(pOutFile, "DC \t%p \t\t# constReleaseVMAccessOutOfLineMask",*((intptr_t*)bufferPos));
1798
bufferPos += sizeof(intptr_t);
1799
1800
debug->printPrefix(pOutFile, NULL, bufferPos, sizeof(intptr_t));
1801
trfprintf(pOutFile, "DC \t%p \t\t# targetAddress",*((intptr_t*)bufferPos));
1802
bufferPos += sizeof(intptr_t);
1803
}
1804
1805