Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/x/codegen/X86HelperLinkage.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/X86HelperLinkage.hpp"
24
25
#include "codegen/Linkage_inlines.hpp"
26
#include "codegen/Machine.hpp"
27
#include "codegen/Register.hpp"
28
#include "codegen/RegisterDependency.hpp"
29
#include "codegen/RegisterPair.hpp"
30
#include "env/jittypes.h"
31
#include "env/VMJ9.h"
32
#include "il/DataTypes.hpp"
33
#include "il/Node.hpp"
34
#include "il/Node_inlines.hpp"
35
#include "il/TreeTop.hpp"
36
#include "il/TreeTop_inlines.hpp"
37
#include "env/VMJ9.h"
38
#include "x/codegen/X86Instruction.hpp"
39
40
// An utility to manage real registers and their corresponding virtual registers
41
class RealRegisterManager
42
{
43
public:
44
RealRegisterManager(TR::CodeGenerator* cg) :
45
_cg(cg),
46
_NumberOfRegistersInUse(0)
47
{
48
memset(_Registers, 0x0, sizeof(_Registers));
49
}
50
~RealRegisterManager()
51
{
52
// RAII: stop using all registers
53
for (uint8_t i = (uint8_t)TR::RealRegister::NoReg; i < (uint8_t)TR::RealRegister::NumRegisters; i++)
54
{
55
if (_Registers[i] != NULL)
56
{
57
_cg->stopUsingRegister(_Registers[i]);
58
}
59
}
60
}
61
// Find or allocate a virtual register which is bind to the given real register
62
TR::Register* Use(TR::RealRegister::RegNum RealRegister)
63
{
64
if (_Registers[RealRegister] == NULL)
65
{
66
bool isGPR = RealRegister >= TR::RealRegister::FirstGPR && RealRegister <= TR::RealRegister::LastGPR;
67
_Registers[RealRegister] = _cg->allocateRegister(isGPR ? TR_GPR : TR_FPR);
68
_NumberOfRegistersInUse++;
69
}
70
return _Registers[RealRegister];
71
}
72
// Build the dependencies for each virtual-real register pair
73
TR::RegisterDependencyConditions* BuildRegisterDependencyConditions()
74
{
75
TR::RegisterDependencyConditions* deps = generateRegisterDependencyConditions(NumberOfRegistersInUse() + 1, // For VMThread
76
NumberOfRegistersInUse() + 1, // For VMThread
77
_cg);
78
for (uint8_t i = (uint8_t)TR::RealRegister::NoReg; i < (uint8_t)TR::RealRegister::NumRegisters; i++)
79
{
80
if (_Registers[i] != NULL)
81
{
82
deps->addPreCondition(_Registers[i], (TR::RealRegister::RegNum)i, _cg);
83
deps->addPostCondition(_Registers[i], (TR::RealRegister::RegNum)i, _cg);
84
}
85
}
86
TR::Register* vmThread = _cg->getVMThreadRegister();
87
deps->addPreCondition(vmThread, (TR::RealRegister::RegNum)vmThread->getAssociation(), _cg);
88
deps->addPostCondition(vmThread, (TR::RealRegister::RegNum)vmThread->getAssociation(), _cg);
89
return deps;
90
}
91
inline uint8_t NumberOfRegistersInUse() const
92
{
93
return _NumberOfRegistersInUse;
94
}
95
96
private:
97
uint8_t _NumberOfRegistersInUse;
98
TR::Register* _Registers[TR::RealRegister::NumRegisters];
99
TR::CodeGenerator* _cg;
100
};
101
102
// On X86-32, fastcall is in-use for both Linux and Windows
103
// On X86-64 Windows, Microsoft x64 calling convention is an extension of fastcall; and hence this code goes through USE_FASTCALL path
104
// On X86-64 Linux, the linkage is System V AMD64 ABI.
105
#if defined(WINDOWS) || defined(TR_TARGET_32BIT)
106
#define USE_FASTCALL
107
#endif
108
109
const TR::RealRegister::RegNum J9::X86::HelperCallSite::IntParamRegisters[] =
110
{
111
#ifdef USE_FASTCALL
112
TR::RealRegister::ecx,
113
TR::RealRegister::edx,
114
#ifdef TR_TARGET_64BIT
115
TR::RealRegister::r8,
116
TR::RealRegister::r9,
117
#endif
118
#else
119
TR::RealRegister::edi,
120
TR::RealRegister::esi,
121
TR::RealRegister::edx,
122
TR::RealRegister::ecx,
123
TR::RealRegister::r8,
124
TR::RealRegister::r9,
125
#endif
126
};
127
128
const TR::RealRegister::RegNum J9::X86::HelperCallSite::CallerSavedRegisters[] =
129
{
130
TR::RealRegister::eax,
131
TR::RealRegister::ecx,
132
TR::RealRegister::edx,
133
#ifndef USE_FASTCALL
134
TR::RealRegister::edi,
135
TR::RealRegister::esi,
136
#endif
137
#ifdef TR_TARGET_64BIT
138
TR::RealRegister::r8,
139
TR::RealRegister::r9,
140
TR::RealRegister::r10,
141
TR::RealRegister::r11,
142
#endif
143
144
TR::RealRegister::xmm0,
145
TR::RealRegister::xmm1,
146
TR::RealRegister::xmm2,
147
TR::RealRegister::xmm3,
148
TR::RealRegister::xmm4,
149
TR::RealRegister::xmm5,
150
TR::RealRegister::xmm6,
151
TR::RealRegister::xmm7,
152
#ifdef TR_TARGET_64BIT
153
TR::RealRegister::xmm8,
154
TR::RealRegister::xmm9,
155
TR::RealRegister::xmm10,
156
TR::RealRegister::xmm11,
157
TR::RealRegister::xmm12,
158
TR::RealRegister::xmm13,
159
TR::RealRegister::xmm14,
160
TR::RealRegister::xmm15,
161
#endif
162
};
163
164
const TR::RealRegister::RegNum J9::X86::HelperCallSite::CalleeSavedRegisters[] =
165
{
166
TR::RealRegister::ebx,
167
#ifdef USE_FASTCALL
168
TR::RealRegister::edi,
169
TR::RealRegister::esi,
170
#endif
171
TR::RealRegister::ebp,
172
TR::RealRegister::esp,
173
#ifdef TR_TARGET_64BIT
174
TR::RealRegister::r12,
175
TR::RealRegister::r13,
176
TR::RealRegister::r14,
177
TR::RealRegister::r15,
178
#endif
179
};
180
181
#undef USE_FASTCALL
182
183
// X86-32 requires callee to cleanup stack, X86-64 requires caller to cleanup stack
184
// Stack slot size is 4 bytes on X86-32 and 8 bytes on X86-64
185
#ifdef TR_TARGET_32BIT
186
const bool J9::X86::HelperCallSite::CalleeCleanup = true;
187
const size_t J9::X86::HelperCallSite::StackSlotSize = 4;
188
#else
189
const bool J9::X86::HelperCallSite::CalleeCleanup = false;
190
const size_t J9::X86::HelperCallSite::StackSlotSize = 8;
191
#endif
192
// Windows X86-64 requires caller reserves shadow space for parameters passed via registers
193
#if defined(WINDOWS) && defined(TR_TARGET_64BIT)
194
const bool J9::X86::HelperCallSite::RegisterParameterShadowOnStack = true;
195
#else
196
const bool J9::X86::HelperCallSite::RegisterParameterShadowOnStack = false;
197
#endif
198
const size_t J9::X86::HelperCallSite::NumberOfIntParamRegisters = sizeof(IntParamRegisters) / sizeof(IntParamRegisters[0]);
199
const size_t J9::X86::HelperCallSite::StackIndexAdjustment = RegisterParameterShadowOnStack ? 0 : NumberOfIntParamRegisters;
200
201
// Code below should not need the #define
202
203
// Calculate preserved register map.
204
// The map is a constant that the C++ compiler *should* be able to determine at compile time
205
static uint32_t X86HelperCallSiteCalculatePreservedRegisterMapForGC()
206
{
207
uint32_t ret = 0;
208
for (size_t i = 0;
209
i < sizeof(J9::X86::HelperCallSite::CalleeSavedRegisters) / sizeof(J9::X86::HelperCallSite::CalleeSavedRegisters[0]);
210
i++)
211
{
212
ret |= TR::RealRegister::gprMask(J9::X86::HelperCallSite::CalleeSavedRegisters[i]);
213
}
214
return ret;
215
}
216
const uint32_t J9::X86::HelperCallSite::PreservedRegisterMapForGC = X86HelperCallSiteCalculatePreservedRegisterMapForGC();
217
218
TR::Register* J9::X86::HelperCallSite::BuildCall()
219
{
220
TR_ASSERT(CalleeCleanup || cg()->getLinkage()->getProperties().getReservesOutgoingArgsInPrologue(),
221
"Caller must reserve outgoing args in prologue unless callee cleans up stack");
222
223
if (cg()->comp()->getOption(TR_TraceCG))
224
{
225
traceMsg(cg()->comp(), "X86 HelperCall: [%04d] %s\n", _SymRef->getReferenceNumber(), cg()->getDebug()->getName(_SymRef));
226
}
227
RealRegisterManager RealRegisters(cg());
228
TR::RealRegister* ESP = cg()->machine()->getRealRegister(TR::RealRegister::esp);
229
230
// Preserve caller saved registers
231
for (size_t i = 0;
232
i < sizeof(CallerSavedRegisters) / sizeof(CallerSavedRegisters[0]);
233
i++)
234
{
235
RealRegisters.Use(CallerSavedRegisters[i]);
236
}
237
// Find the return register, EAX/RAX
238
TR::Register* EAX = RealRegisters.Use(TR::RealRegister::eax);
239
240
// Build parameters, parameters in _Params are Right-to-Left (RTL)
241
int NumberOfParamOnStack = 0;
242
for (size_t i = 0; i < _Params.size(); i++)
243
{
244
size_t index = _Params.size() - i - 1;
245
if (index < NumberOfIntParamRegisters)
246
{
247
generateRegRegInstruction(TR::InstOpCode::MOVRegReg(),
248
_Node,
249
RealRegisters.Use(IntParamRegisters[index]),
250
_Params[i],
251
cg());
252
}
253
else
254
{
255
NumberOfParamOnStack++;
256
if (CalleeCleanup)
257
{
258
generateRegInstruction(TR::InstOpCode::PUSHReg, _Node, _Params[i], cg());
259
}
260
else
261
{
262
size_t offset = StackSlotSize * (index - StackIndexAdjustment);
263
generateMemRegInstruction(TR::InstOpCode::SMemReg(),
264
_Node,
265
generateX86MemoryReference(ESP, offset, cg()),
266
_Params[i],
267
cg());
268
}
269
}
270
}
271
272
// Call helper
273
TR::X86ImmInstruction* instr = generateImmSymInstruction(TR::InstOpCode::CALLImm4,
274
_Node,
275
(uintptr_t)_SymRef->getMethodAddress(),
276
_SymRef,
277
RealRegisters.BuildRegisterDependencyConditions(),
278
cg());
279
instr->setNeedsGCMap(PreservedRegisterMapForGC);
280
281
// Stack adjustment
282
{
283
int SizeOfParamOnStack = StackSlotSize * (NumberOfParamOnStack + NumberOfIntParamRegisters - StackIndexAdjustment);
284
if (CalleeCleanup)
285
{
286
instr->setAdjustsFramePointerBy(-SizeOfParamOnStack);
287
}
288
else
289
{
290
if (SizeOfParamOnStack > cg()->getLargestOutgoingArgSize())
291
{
292
cg()->setLargestOutgoingArgSize(SizeOfParamOnStack);
293
}
294
}
295
}
296
297
// Return value
298
TR::Register* ret = NULL;
299
switch (_ReturnType)
300
{
301
case TR::NoType:
302
break;
303
case TR::Address:
304
ret = cg()->allocateCollectedReferenceRegister();
305
break;
306
case TR::Int8:
307
case TR::Int16:
308
case TR::Int32:
309
#ifdef TR_TARGET_64BIT
310
case TR::Int64:
311
#endif
312
ret = cg()->allocateRegister();
313
break;
314
default:
315
TR_ASSERT(false, "Unsupported call return data type: #%d", (int)_ReturnType);
316
break;
317
}
318
if (ret)
319
{
320
generateRegRegInstruction(TR::InstOpCode::MOVRegReg(), _Node, ret, EAX, cg());
321
}
322
323
if (cg()->canEmitBreakOnDFSet())
324
generateBreakOnDFSet(cg());
325
326
return ret;
327
}
328
329