Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/z/codegen/S390CHelperLinkage.cpp
6004 views
1
/*******************************************************************************
2
* Copyright (c) 2000, 2021 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21
*******************************************************************************/
22
23
#include "codegen/S390CHelperLinkage.hpp"
24
#include "codegen/S390PrivateLinkage.hpp"
25
26
#include "codegen/CodeGenerator.hpp"
27
#include "codegen/GCStackAtlas.hpp"
28
#include "codegen/Linkage_inlines.hpp"
29
#include "codegen/Snippet.hpp"
30
#include "compile/ResolvedMethod.hpp"
31
#include "compile/VirtualGuard.hpp"
32
#include "env/CHTable.hpp"
33
#include "env/CompilerEnv.hpp"
34
#include "env/J2IThunk.hpp"
35
#include "env/PersistentCHTable.hpp"
36
#include "env/StackMemoryRegion.hpp"
37
#include "env/VMJ9.h"
38
#include "env/jittypes.h"
39
#include "env/j9method.h"
40
#include "il/Node.hpp"
41
#include "il/Node_inlines.hpp"
42
#include "il/TreeTop.hpp"
43
#include "il/TreeTop_inlines.hpp"
44
#include "infra/InterferenceGraph.hpp"
45
#include "z/codegen/OpMemToMem.hpp"
46
#include "z/codegen/S390Evaluator.hpp"
47
#include "z/codegen/S390GenerateInstructions.hpp"
48
#include "z/codegen/S390HelperCallSnippet.hpp"
49
#include "z/codegen/S390J9CallSnippet.hpp"
50
#include "z/codegen/S390StackCheckFailureSnippet.hpp"
51
#include "z/codegen/SystemLinkage.hpp"
52
#include "runtime/J9Profiler.hpp"
53
#include "runtime/J9ValueProfiler.hpp"
54
55
////////////////////////////////////////////////////////////////////////////////
56
// J9::Z::CHelperLinkage for J9
57
////////////////////////////////////////////////////////////////////////////////
58
J9::Z::CHelperLinkage::CHelperLinkage(TR::CodeGenerator * codeGen,TR_LinkageConventions elc)
59
: TR::Linkage(codeGen,elc)
60
{
61
TR::Compilation *comp = codeGen->comp();
62
63
// Common Linux on Z and z/OS linkage settings
64
setRegisterFlag(TR::RealRegister::GPR8, Preserved);
65
setRegisterFlag(TR::RealRegister::GPR9, Preserved);
66
setRegisterFlag(TR::RealRegister::GPR10, Preserved);
67
setRegisterFlag(TR::RealRegister::GPR11, Preserved);
68
setRegisterFlag(TR::RealRegister::GPR13, Preserved);
69
setRegisterFlag(TR::RealRegister::GPR15, Preserved);
70
71
#if defined(ENABLE_PRESERVED_FPRS)
72
// In case of 32bit Linux on Z, System Linkage only preserves FPR4 and FPR6. For all other targets, FPR8-FPR15 is
73
// preserved.
74
if (comp->target().isLinux() && comp->target().is32Bit())
75
{
76
setRegisterFlag(TR::RealRegister::FPR4, Preserved);
77
setRegisterFlag(TR::RealRegister::FPR6, Preserved);
78
}
79
else
80
{
81
setRegisterFlag(TR::RealRegister::FPR8, Preserved);
82
setRegisterFlag(TR::RealRegister::FPR9, Preserved);
83
setRegisterFlag(TR::RealRegister::FPR10, Preserved);
84
setRegisterFlag(TR::RealRegister::FPR11, Preserved);
85
setRegisterFlag(TR::RealRegister::FPR12, Preserved);
86
setRegisterFlag(TR::RealRegister::FPR13, Preserved);
87
setRegisterFlag(TR::RealRegister::FPR14, Preserved);
88
setRegisterFlag(TR::RealRegister::FPR15, Preserved);
89
}
90
#endif
91
92
// Platform specific linkage settings
93
if (comp->target().isLinux())
94
{
95
setRegisterFlag(TR::RealRegister::GPR6, Preserved);
96
setRegisterFlag(TR::RealRegister::GPR7, Preserved);
97
setRegisterFlag(TR::RealRegister::GPR12, Preserved);
98
99
setReturnAddressRegister(TR::RealRegister::GPR14);
100
setIntegerReturnRegister(TR::RealRegister::GPR2);
101
setLongReturnRegister(TR::RealRegister::GPR2);
102
setIntegerArgumentRegister(0, TR::RealRegister::GPR2);
103
setIntegerArgumentRegister(1, TR::RealRegister::GPR3);
104
setIntegerArgumentRegister(2, TR::RealRegister::GPR4);
105
setIntegerArgumentRegister(3, TR::RealRegister::GPR5);
106
setIntegerArgumentRegister(4, TR::RealRegister::GPR6);
107
108
// Hardcoding register map for GC can lead to subtle bugs if linkage is changed and we did not change register map for GC.
109
// TODO We should write a function that goes through the list of preserved registers and prepare register map for GC.
110
setPreservedRegisterMapForGC(0x0000BFC0);
111
112
// GPR5 needs to be stored before using it as argument register.
113
// Right now setting number of integer argument registers to 3.
114
// TODO When we add support for more than 3 arguments, we should change this number to 5.
115
setNumIntegerArgumentRegisters(3);
116
}
117
118
if (comp->target().isZOS())
119
{
120
setRegisterFlag(TR::RealRegister::GPR14, Preserved);
121
122
if (comp->target().is64Bit())
123
{
124
setRegisterFlag(TR::RealRegister::GPR12, Preserved);
125
126
setPreservedRegisterMapForGC(0x0000FF00);
127
}
128
else
129
{
130
// 31-Bit zOS will need GPR12 for CAA register so it won't be preserved. For all other variant it is preserved
131
setPreservedRegisterMapForGC(0x0000EF00);
132
}
133
134
if (codeGen->getSupportsVectorRegisters())
135
{
136
setRegisterFlag(TR::RealRegister::VRF16, Preserved);
137
setRegisterFlag(TR::RealRegister::VRF17, Preserved);
138
setRegisterFlag(TR::RealRegister::VRF18, Preserved);
139
setRegisterFlag(TR::RealRegister::VRF19, Preserved);
140
setRegisterFlag(TR::RealRegister::VRF20, Preserved);
141
setRegisterFlag(TR::RealRegister::VRF21, Preserved);
142
setRegisterFlag(TR::RealRegister::VRF22, Preserved);
143
setRegisterFlag(TR::RealRegister::VRF23, Preserved);
144
}
145
146
setReturnAddressRegister(TR::RealRegister::GPR7);
147
setIntegerReturnRegister(TR::RealRegister::GPR3);
148
setLongReturnRegister(TR::RealRegister::GPR3);
149
setIntegerArgumentRegister(0, TR::RealRegister::GPR1);
150
setIntegerArgumentRegister(1, TR::RealRegister::GPR2);
151
setIntegerArgumentRegister(2, TR::RealRegister::GPR3);
152
setNumIntegerArgumentRegisters(3);
153
154
#if defined(J9ZOS390)
155
setDSAPointerRegister(TR::RealRegister::GPR4);
156
#if defined(TR_HOST_32BIT)
157
setCAAPointerRegister(TR::RealRegister::GPR12);
158
#endif
159
#endif
160
}
161
162
setLongLowReturnRegister(TR::RealRegister::GPR3);
163
setLongHighReturnRegister(TR::RealRegister::GPR2);
164
setFloatReturnRegister(TR::RealRegister::FPR0);
165
setDoubleReturnRegister(TR::RealRegister::FPR0);
166
setLongDoubleReturnRegister0(TR::RealRegister::FPR0);
167
setLongDoubleReturnRegister2(TR::RealRegister::FPR2);
168
setLongDoubleReturnRegister4(TR::RealRegister::FPR4);
169
setLongDoubleReturnRegister6(TR::RealRegister::FPR6);
170
setStackPointerRegister(TR::RealRegister::GPR5);
171
setMethodMetaDataRegister(TR::RealRegister::GPR13);
172
}
173
174
175
// Utility to Manage RealRegisters for Helper Call Using C Linkage
176
/** \brief Utility to Manage RealRegisters for Helper Call Using C Linkage.
177
* \details
178
* It is used to allocate a virtual register and assign them to the requested real register.
179
*/
180
class RealRegisterManager
181
{
182
public:
183
RealRegisterManager(TR::CodeGenerator *cg) :
184
_cg(cg),
185
_numberOfRegistersInUse(0)
186
{
187
memset(_Registers, 0x0, sizeof(_Registers));
188
}
189
190
~RealRegisterManager()
191
{
192
for(uint8_t i = (uint8_t)TR::RealRegister::NoReg; i < (uint8_t)TR::RealRegister::NumRegisters; i++)
193
{
194
if (_Registers[i] != NULL)
195
{
196
_cg->stopUsingRegister(_Registers[i]);
197
}
198
}
199
}
200
TR::Register* use(TR::RealRegister::RegNum RealRegister)
201
{
202
if (_Registers[RealRegister] == NULL)
203
{
204
if (RealRegister >= TR::RealRegister::FirstFPR && RealRegister <= TR::RealRegister::LastFPR)
205
_Registers[RealRegister] = _cg->allocateRegister(TR_FPR);
206
else if (RealRegister >= TR::RealRegister::FirstVRF && RealRegister <= TR::RealRegister::LastVRF)
207
_Registers[RealRegister] = _cg->allocateRegister(TR_VRF);
208
else
209
_Registers[RealRegister] = _cg->allocateRegister();
210
_numberOfRegistersInUse++;
211
}
212
return _Registers[RealRegister];
213
}
214
// For the post dependency conditions we need return address register to be assigned to proper virtual register instead of the dummy virtual register
215
TR::RegisterDependencyConditions* buildRegisterDependencyConditions(TR::RealRegister::RegNum returnAddressReg)
216
{
217
uint32_t numDeps = numberOfRegistersInUse() - 1 + (_cg->comp()->target().is32Bit() ? 1 : 0);
218
219
// Helper function to generate RegisterDependencyCondition adds one more to post deps for return address.
220
// Hence asking one less post deps so this won't create a problem when combined with other dependency condition for ICF.
221
TR::RegisterDependencyConditions* deps = generateRegisterDependencyConditions(0, numDeps, _cg);
222
for (uint8_t i = (uint8_t)TR::RealRegister::NoReg; i < (uint8_t)TR::RealRegister::NumRegisters; i++)
223
{
224
if (_Registers[i] != NULL)
225
{
226
if (i != returnAddressReg)
227
_Registers[i]->setPlaceholderReg();
228
deps->addPostCondition(_Registers[i], (TR::RealRegister::RegNum)i, DefinesDependentRegister);
229
}
230
}
231
232
// spill all high regs
233
//
234
if (_cg->comp()->target().is32Bit())
235
{
236
TR::Register *reg = _cg->allocateRegister();
237
deps->addPostCondition(reg, TR::RealRegister::KillVolHighRegs);
238
_cg->stopUsingRegister(reg);
239
}
240
return deps;
241
}
242
243
inline uint8_t numberOfRegistersInUse() const
244
{
245
return _numberOfRegistersInUse;
246
}
247
private:
248
uint8_t _numberOfRegistersInUse;
249
TR::Register* _Registers[TR::RealRegister::NumRegisters];
250
TR::CodeGenerator* _cg;
251
};
252
253
/** \brief Build a JIT helper call.
254
* \details
255
* It generates sequence that prepares parameters for the JIT helper function and generate a helper call.
256
* \param callNode The node for which you are generating a helper call
257
* \param deps The pre register dependency conditions that will be filled by this function to attach within ICF
258
* \param returnReg TR::Register* allocated by consumer of this API to hold the result of the helper call,
259
* If passed, this function uses it to store return value from helper instead of allocating new register
260
* \return TR::Register *helperReturnResult, gets the return value of helper function and return to the evaluator.
261
*/
262
TR::Register * J9::Z::CHelperLinkage::buildDirectDispatch(TR::Node * callNode, TR::RegisterDependencyConditions **deps, TR::Register *returnReg)
263
{
264
RealRegisterManager RealRegisters(cg());
265
bool isHelperCallWithinICF = deps != NULL;
266
// TODO: Currently only jitInstanceOf is fast path helper. Need to modify following condition if we add support for other fast path only helpers
267
bool isFastPathOnly = callNode->getOpCodeValue() == TR::instanceof;
268
traceMsg(comp(),"%s: Internal Control Flow in OOL : %s\n",callNode->getOpCode().getName(),isHelperCallWithinICF ? "true" : "false" );
269
for (int i = TR::RealRegister::FirstGPR; i < TR::RealRegister::NumRegisters; i++)
270
{
271
if (!self()->getPreserved(REGNUM(i)) && cg()->machine()->getRealRegister(i)->getState() != TR::RealRegister::Locked)
272
{
273
RealRegisters.use((TR::RealRegister::RegNum)i);
274
}
275
}
276
TR::RegisterDependencyConditions *childNodeRegDeps = generateRegisterDependencyConditions(0,callNode->getNumChildren(), cg());
277
TR::RegisterDependencyConditions* preDeps = generateRegisterDependencyConditions(callNode->getNumChildren()+1, 0, cg());
278
TR::Register *vmThreadRegister = cg()->getMethodMetaDataRealRegister();
279
TR::Register *vmThreadArgReg = cg()->allocateRegister();
280
generateRRInstruction(cg(), TR::InstOpCode::getLoadRegOpCode(), callNode, vmThreadArgReg, vmThreadRegister);
281
preDeps->addPreCondition(vmThreadArgReg, getIntegerArgumentRegister(0));
282
// TODO For Time Being, it is expected that param number won't increase beyond 3 need to fix this when support for stack is there
283
for (int i=0; i< callNode->getNumChildren(); i++)
284
{
285
if (i < self()->getNumIntegerArgumentRegisters()-1)
286
preDeps->addPreCondition(cg()->gprClobberEvaluate(callNode->getChild(i)), getIntegerArgumentRegister(i+1));
287
else
288
TR_ASSERT(false,"Parameters on Stack not supported yet");
289
childNodeRegDeps->addPostConditionIfNotAlreadyInserted(callNode->getChild(i)->getRegister(), TR::RealRegister::AssignAny);
290
}
291
292
TR::Register *javaStackPointerRegister = NULL;
293
/* On zOS, we need to use GPR7 as return address for fastPath helper calls
294
* Following line will use the System linkage's return address register for fast path
295
* And for regular dual mode helper, private linkage's return address register
296
*/
297
TR::RealRegister::RegNum regRANum = isFastPathOnly ? self()->getReturnAddressRegister() : cg()->getReturnAddressRegister();
298
TR::Register *regRA = RealRegisters.use(regRANum);
299
#if defined(J9ZOS390)
300
TR::Register *DSAPointerReg = NULL;
301
uint32_t offsetOfSSP = static_cast<uint32_t>(offsetof(J9VMThread, systemStackPointer));
302
uint32_t pointerSize = comp()->target().is64Bit() ? 7 : 3;
303
#endif
304
305
TR::RegisterDependencyConditions * postDeps = RealRegisters.buildRegisterDependencyConditions(regRANum);
306
// If buildDirectDispatch is called within ICF we need to pass the dependencies which will be used there, else we need single dependencylist to be attached to the BRASL
307
// We return postdependency conditions back to evaluator to merge with ICF condition and attach to merge label
308
if (isHelperCallWithinICF )
309
*deps = new (cg()->trHeapMemory()) TR::RegisterDependencyConditions(postDeps, childNodeRegDeps, cg());
310
311
int padding = 0;
312
uint32_t offsetJ9SP = static_cast<uint32_t>(offsetof(J9VMThread, sp));
313
TR::Instruction *cursor = NULL;
314
315
/* Following routine will generate assembly routine as following
316
* #if (fastPathHelper)
317
* STG R5, @(vmThread+offsetOf(J9SP))
318
* #define zOS
319
* LG DSA, @(vmThread,offsetOfSSP)
320
* XC offsetOFSSP(vmThread, pointerSize), offsetOfSSP(vmThread)
321
* #define 32Bit
322
* LG CAA, @(DSA+CAAOffset)
323
* #endif
324
* BRASL R14,JIThelper
325
* #if fastPathHelper
326
* #define zOS
327
* NOP // Padding for zOS return from helper
328
* STG DSA, @(vmThread, offsetOfSSP)
329
* LG R5, @(vmThread, offsetOfJ9SP)
330
* #endif
331
*/
332
333
if (isFastPathOnly)
334
{
335
// Storing Java Stack Pointer
336
javaStackPointerRegister = cg()->getStackPointerRealRegister();
337
cursor = generateRXInstruction(cg(), TR::InstOpCode::getStoreOpCode(), callNode, javaStackPointerRegister, generateS390MemoryReference(vmThreadRegister, offsetJ9SP, cg()));
338
#if defined(J9ZOS390)
339
padding += 2;
340
// Loading DSAPointer Register
341
DSAPointerReg = RealRegisters.use(getDSAPointerRegister());
342
generateRXInstruction(cg(), TR::InstOpCode::getLoadOpCode(), callNode, DSAPointerReg, generateS390MemoryReference(vmThreadRegister, offsetOfSSP, cg()));
343
generateSS1Instruction(cg(), TR::InstOpCode::XC, callNode, pointerSize,
344
generateS390MemoryReference(vmThreadRegister, offsetOfSSP, cg()),
345
generateS390MemoryReference(vmThreadRegister, offsetOfSSP, cg()));
346
#if defined(TR_HOST_32BIT)
347
padding += 2;
348
// Loading CAA Pointer Register
349
TR::Register *CAAPointerReg = RealRegisters.use(getCAAPointerRegister());
350
TR_J9VMBase *fej9 = (TR_J9VMBase *) comp()->fe();
351
int32_t J9TR_CAA_save_offset = fej9->getCAASaveOffset();
352
generateRXInstruction(cg(), TR::InstOpCode::getLoadOpCode(), callNode, CAAPointerReg, generateS390MemoryReference(DSAPointerReg, J9TR_CAA_save_offset, cg()));
353
#endif
354
#endif
355
}
356
TR::SymbolReference * callSymRef = callNode->getSymbolReference();
357
void * destAddr = callNode->getSymbolReference()->getSymbol()->castToMethodSymbol()->getMethodAddress();
358
cursor = new (cg()->trHeapMemory()) TR::S390RILInstruction(TR::InstOpCode::BRASL, callNode, regRA, destAddr, callSymRef, cg());
359
cursor->setDependencyConditions(preDeps);
360
if (isFastPathOnly)
361
{
362
#if defined(J9ZOS390)
363
/**
364
* Same as SystemLinkage call builder class, a NOP padding is needed because returning from XPLINK functions
365
* skips the XPLink eyecatcher and always return to a point that's 2 or 4 bytes after the return address.
366
*
367
* In 64 bit XPLINK, the caller returns with a 'branch relative on condition' instruction with a 2 byte offset:
368
*
369
* 0x47F07002 B 2(,r7)
370
*
371
* In 31-bit XPLINK, this offset is 4-byte.
372
*
373
* As a result of this, JIT'ed code that does XPLINK calls needs 2 or 4-byte NOP paddings to ensure entry to valid instruction.
374
*
375
* The BASR and NOP padding must stick together and can't have reverse spills in the middle.
376
* Hence, splitting the dependencies to avoid spill instructions.
377
*/
378
379
cursor = new (cg()->trHeapMemory()) TR::S390NOPInstruction(TR::InstOpCode::NOP, padding, callNode, cursor, cg());
380
// Storing DSA Register back
381
cursor = generateRXInstruction(cg(), TR::InstOpCode::getStoreOpCode(), callNode, DSAPointerReg, generateS390MemoryReference(vmThreadRegister, offsetOfSSP, cg()), cursor);
382
#endif
383
// Reloading Java Stack pointer
384
cursor = generateRXInstruction(cg(), TR::InstOpCode::getLoadOpCode(), callNode, javaStackPointerRegister, generateS390MemoryReference(vmThreadRegister, offsetJ9SP, cg()), cursor);
385
}
386
else
387
{
388
// Fastpath helper do not expects GC call in-between so only attaching them for normal dual mode helpers
389
// As GC map is attached to instruction after RA is done, it is guaranteed that all the non-preserved register by system linkage are either stored in preserved register
390
// Or spilled to stack. We only need to mark preserved register in GC map. Only possibility of non-preserved register containing a live object is in argument to helper which should be a clobberable copy of actual object.
391
cursor->setNeedsGCMap(getPreservedRegisterMapForGC());
392
}
393
394
// If helper call is fast path helper call and is not within ICF,
395
// We need to attach post dependency to the restoring of java stack pointer.
396
// This will assure that reverse spilling occurs after restoring of java stack pointer
397
if (!isHelperCallWithinICF)
398
cursor->setDependencyConditions(postDeps);
399
preDeps->stopUsingDepRegs(cg());
400
// Logic To Handle Return Register
401
TR::DataType returnType = callNode->getDataType();
402
if (returnReg == NULL)
403
{
404
switch(returnType)
405
{
406
case TR::NoType:
407
traceMsg(comp(), "ReturnType = %s\n",returnType.toString());
408
break;
409
case TR::Address:
410
traceMsg(comp(), "ReturnType = %s\n",returnType.toString());
411
returnReg = cg()->allocateCollectedReferenceRegister();
412
break;
413
case TR::Int8:
414
case TR::Int16:
415
case TR::Int32:
416
#ifdef TR_TARGET_64BIT
417
case TR::Int64:
418
#endif
419
traceMsg(comp(), "ReturnType = %s\n",returnType.toString());
420
returnReg = cg()->allocateRegister();
421
break;
422
default:
423
TR_ASSERT(false, "Unsupported Call return data type: %s\n", returnType.toString());
424
break;
425
}
426
}
427
// We need to fill returnReg only if it requested by evaluator or node returns value or address
428
if (returnReg != NULL)
429
generateRRInstruction(cg(), TR::InstOpCode::getLoadRegOpCode(), callNode, returnReg, RealRegisters.use(isFastPathOnly ? getIntegerReturnRegister():getLongHighReturnRegister()), cursor);
430
431
return returnReg;
432
}
433
434