Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/x/i386/codegen/IA32JNILinkage.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
#if defined(TR_TARGET_32BIT)
24
25
#include "codegen/IA32JNILinkage.hpp"
26
27
#include "codegen/CodeGenerator.hpp"
28
#include "codegen/Linkage.hpp"
29
#include "codegen/Linkage_inlines.hpp"
30
#include "codegen/MemoryReference.hpp"
31
#include "codegen/RealRegister.hpp"
32
#include "codegen/Register.hpp"
33
#include "codegen/RegisterPair.hpp"
34
#include "codegen/Snippet.hpp"
35
#include "compile/ResolvedMethod.hpp"
36
#include "env/jittypes.h"
37
#include "env/CompilerEnv.hpp"
38
#include "il/LabelSymbol.hpp"
39
#include "il/MethodSymbol.hpp"
40
#include "il/Node.hpp"
41
#include "il/Node_inlines.hpp"
42
#include "il/RegisterMappedSymbol.hpp"
43
#include "il/ResolvedMethodSymbol.hpp"
44
#include "il/StaticSymbol.hpp"
45
#include "il/Symbol.hpp"
46
#include "il/SymbolReference.hpp"
47
#include "env/VMJ9.h"
48
#include "runtime/Runtime.hpp"
49
#include "x/codegen/CheckFailureSnippet.hpp"
50
#include "x/codegen/IA32LinkageUtils.hpp"
51
#include "x/codegen/X86Instruction.hpp"
52
53
54
TR::Register *J9::X86::I386::JNILinkage::buildDirectDispatch(TR::Node *callNode, bool spillFPRegs)
55
{
56
TR::MethodSymbol* methodSymbol = callNode->getSymbolReference()->getSymbol()->castToMethodSymbol();
57
TR_ASSERT(methodSymbol->isJNI(), "J9::X86::I386::JNILinkage::buildDirectDispatch can't hanlde this case.\n");
58
return buildJNIDispatch(callNode);
59
}
60
61
TR::Register *J9::X86::I386::JNILinkage::buildJNIDispatch(TR::Node *callNode)
62
{
63
#ifdef DEBUG
64
if (debug("reportJNI"))
65
{
66
printf("JNI Dispatch: %s calling %s\n", comp()->signature(), comp()->getDebug()->getName(callNode->getSymbolReference()));
67
}
68
#endif
69
70
TR::RegisterDependencyConditions *deps = generateRegisterDependencyConditions((uint8_t)0, 20, cg());
71
72
TR::SymbolReference *callSymRef = callNode->getSymbolReference();
73
TR::MethodSymbol *callSymbol = callSymRef->getSymbol()->castToMethodSymbol();
74
TR::ResolvedMethodSymbol *resolvedMethodSymbol = callSymbol->castToResolvedMethodSymbol();
75
TR_ResolvedMethod *resolvedMethod = resolvedMethodSymbol->getResolvedMethod();
76
TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());
77
bool dropVMAccess = !fej9->jniRetainVMAccess(resolvedMethod);
78
bool isJNIGCPoint = !fej9->jniNoGCPoint(resolvedMethod);
79
bool killNonVolatileGPRs = isJNIGCPoint;
80
bool checkExceptions = !fej9->jniNoExceptionsThrown(resolvedMethod);
81
bool createJNIFrame = !fej9->jniNoNativeMethodFrame(resolvedMethod);
82
bool tearDownJNIFrame = !fej9->jniNoSpecialTeardown(resolvedMethod);
83
bool wrapRefs = !fej9->jniDoNotWrapObjects(resolvedMethod);
84
bool passReceiver = !fej9->jniDoNotPassReceiver(resolvedMethod);
85
bool passThread = !fej9->jniDoNotPassThread(resolvedMethod);
86
87
if (resolvedMethodSymbol->canDirectNativeCall())
88
{
89
dropVMAccess = false;
90
killNonVolatileGPRs = false;
91
isJNIGCPoint = false;
92
checkExceptions = false;
93
createJNIFrame = false;
94
tearDownJNIFrame = false;
95
}
96
else if (callSymbol->isPureFunction())
97
{
98
dropVMAccess = false;
99
isJNIGCPoint = false;
100
checkExceptions = false;
101
}
102
103
TR::Register* ebpReal = cg()->getVMThreadRegister();
104
TR::RealRegister* espReal = cg()->machine()->getRealRegister(TR::RealRegister::esp);
105
TR::LabelSymbol* returnAddrLabel = NULL;
106
107
// Build parameters
108
int32_t argSize = buildParametersOnCStack(callNode, passReceiver ? 0 : 1, passThread, true);
109
110
// JNI Call
111
TR::LabelSymbol* begLabel = generateLabelSymbol(cg());
112
TR::LabelSymbol* endLabel = generateLabelSymbol(cg());
113
begLabel->setStartInternalControlFlow();
114
endLabel->setEndInternalControlFlow();
115
116
generateLabelInstruction(TR::InstOpCode::label, callNode, begLabel, cg());
117
118
// Save VFP
119
TR::X86VFPSaveInstruction* vfpSave = generateVFPSaveInstruction(callNode, cg());
120
121
returnAddrLabel = generateLabelSymbol(cg());
122
if (createJNIFrame)
123
{
124
// Anchored frame pointer register.
125
//
126
TR::RealRegister *ebxReal = cg()->machine()->getRealRegister(TR::RealRegister::ebx);
127
128
129
// Begin: mask out the magic bit that indicates JIT frames below
130
//
131
generateMemImmInstruction(
132
TR::InstOpCode::S4MemImm4,
133
callNode,
134
generateX86MemoryReference(ebpReal, fej9->thisThreadGetJavaFrameFlagsOffset(), cg()),
135
0,
136
cg()
137
);
138
// End: mask out the magic bit that indicates JIT frames below
139
140
ebxReal->setHasBeenAssignedInMethod(true);
141
142
// Build stack frame in java stack.
143
// Tag current bp.
144
//
145
uint32_t tagBits = fej9->constJNICallOutFrameSpecialTag();
146
147
// If the current method is simply a wrapper for the JNI call, hide the call-out stack frame.
148
//
149
if (resolvedMethod == comp()->getCurrentMethod())
150
{
151
tagBits |= fej9->constJNICallOutFrameInvisibleTag();
152
}
153
154
// Push tag bits (savedA0 slot).
155
//
156
generateImmInstruction(TR::InstOpCode::PUSHImm4, callNode, tagBits, cg());
157
158
// Allocate space to get to frame size for special frames (skip savedPC slot).
159
//
160
generateRegImmInstruction(TR::InstOpCode::SUB4RegImms, callNode, espReal, 4, cg());
161
162
// Push return address in this frame (savedCP slot).
163
//
164
TR::X86LabelInstruction* returnAddrLabelInstruction = generateLabelInstruction(TR::InstOpCode::PUSHImm4, callNode, returnAddrLabel, cg());
165
returnAddrLabelInstruction->setReloType(TR_AbsoluteMethodAddress);
166
167
// Push frame flags.
168
//
169
generateImmInstruction(TR::InstOpCode::PUSHImm4, callNode, fej9->constJNICallOutFrameFlags(), cg());
170
171
// Push the RAM method for the native.
172
//
173
static const TR_ExternalRelocationTargetKind reloTypes[] = {TR_VirtualRamMethodConst, TR_NoRelocation /*Interfaces*/, TR_StaticRamMethodConst, TR_SpecialRamMethodConst};
174
int rType = resolvedMethodSymbol->getMethodKind()-1; //method kinds are 1-based
175
TR_ASSERT(reloTypes[rType] != TR_NoRelocation, "There shouldn't be direct JNI interface calls!");
176
generateImmInstruction(TR::InstOpCode::PUSHImm4, callNode, (uintptr_t) resolvedMethod->resolvedMethodAddress(), cg(), reloTypes[rType]);
177
178
// Store out pc and literals values indicating the callout frame.
179
//
180
generateMemImmInstruction(
181
TR::InstOpCode::S4MemImm4,
182
callNode,
183
generateX86MemoryReference(ebpReal, fej9->thisThreadGetJavaPCOffset(), cg()),
184
fej9->constJNICallOutFrameType(),
185
cg()
186
);
187
generateMemImmInstruction(
188
TR::InstOpCode::S4MemImm4,
189
callNode,
190
generateX86MemoryReference(ebpReal, fej9->thisThreadGetJavaLiteralsOffset(), cg()),
191
0,
192
cg()
193
);
194
}
195
196
// Store out jsp.
197
//
198
generateMemRegInstruction(
199
TR::InstOpCode::S4MemReg,
200
callNode,
201
generateX86MemoryReference(ebpReal, fej9->thisThreadGetJavaSPOffset(), cg()),
202
espReal,
203
cg()
204
);
205
206
// Switch stacks.
207
// Load up machine SP.
208
//
209
generateRegMemInstruction(
210
TR::InstOpCode::L4RegMem,
211
callNode,
212
espReal,
213
generateX86MemoryReference(ebpReal, ((TR_J9VMBase *) fej9)->thisThreadGetMachineSPOffset(), cg()),
214
cg()
215
);
216
217
// Save ESP to EDI, a callee preserved register
218
// It is necessary because the JNI method may be either caller-cleanup or callee-cleanup
219
TR::Register *ediReal = cg()->allocateRegister();
220
generateRegRegInstruction(TR::InstOpCode::MOV4RegReg, callNode, ediReal, espReal, cg());
221
generateRegImmInstruction(argSize >= -128 && argSize <= 127 ? TR::InstOpCode::SUB4RegImms : TR::InstOpCode::SUB4RegImm4, callNode, espReal, argSize, cg());
222
223
// We have to be careful to allocate the return register after the
224
// dependency conditions for the other killed registers have been set up,
225
// otherwise it will be marked as interfering with them.
226
// Start by creating a dummy post condition and then fill it in after the
227
// others have been set up.
228
//
229
deps->addPostCondition(NULL, TR::RealRegister::ecx, cg());
230
231
TR::Register *esiReal;
232
TR::Register *eaxReal;
233
TR::Register *edxReal;
234
TR::Register *ebxReal;
235
eaxReal = cg()->allocateRegister();
236
deps->addPostCondition(eaxReal, TR::RealRegister::eax, cg());
237
cg()->stopUsingRegister(eaxReal);
238
239
edxReal = cg()->allocateRegister();
240
deps->addPostCondition(NULL, TR::RealRegister::edx, cg());
241
242
ebxReal = cg()->allocateRegister();
243
deps->addPostCondition(ebxReal, TR::RealRegister::ebx, cg());
244
cg()->stopUsingRegister(ebxReal);
245
246
deps->addPostCondition(ediReal, TR::RealRegister::edi, cg());
247
248
esiReal = cg()->allocateRegister();
249
deps->addPostCondition(esiReal, TR::RealRegister::esi, cg());
250
cg()->stopUsingRegister(esiReal);
251
252
deps->getPostConditions()->setDependencyInfo(2, edxReal, TR::RealRegister::edx, cg());
253
if (!callNode->getType().isInt64())
254
cg()->stopUsingRegister(edxReal);
255
256
TR::Register *ecxReal;
257
if (callNode->getDataType() == TR::Address)
258
ecxReal = cg()->allocateCollectedReferenceRegister();
259
else
260
ecxReal = cg()->allocateRegister();
261
deps->getPostConditions()->setDependencyInfo(0, ecxReal, TR::RealRegister::ecx, cg());
262
if (callNode->getDataType() == TR::NoType)
263
cg()->stopUsingRegister(ecxReal);
264
265
// Kill all the xmm registers across the JNI callout sequence.
266
//
267
for (int i = 0; i <= 7; i++)
268
{
269
TR::Register *xmm_i = cg()->allocateRegister(TR_FPR);
270
deps->addPostCondition(xmm_i, TR::RealRegister::xmmIndex(i), cg());
271
cg()->stopUsingRegister(xmm_i);
272
}
273
274
if (dropVMAccess)
275
{
276
generateMemImmInstruction(TR::InstOpCode::S4MemImm4,
277
callNode,
278
generateX86MemoryReference(ebpReal, offsetof(struct J9VMThread, inNative), cg()),
279
1,
280
cg());
281
282
#if !defined(J9VM_INTERP_ATOMIC_FREE_JNI_USES_FLUSH)
283
TR::MemoryReference *mr = generateX86MemoryReference(espReal, intptr_t(0), cg());
284
mr->setRequiresLockPrefix();
285
generateMemImmInstruction(TR::InstOpCode::OR4MemImms, callNode, mr, 0, cg());
286
#endif /* !J9VM_INTERP_ATOMIC_FREE_JNI_USES_FLUSH */
287
288
TR::LabelSymbol *longReleaseSnippetLabel = generateLabelSymbol(cg());
289
TR::LabelSymbol *longReleaseRestartLabel = generateLabelSymbol(cg());
290
291
static_assert(J9_PUBLIC_FLAGS_VM_ACCESS <= 0x7fffffff, "VM access bit must be immediate");
292
generateMemImmInstruction(TR::InstOpCode::CMP4MemImm4,
293
callNode,
294
generateX86MemoryReference(ebpReal, fej9->thisThreadGetPublicFlagsOffset(), cg()),
295
J9_PUBLIC_FLAGS_VM_ACCESS,
296
cg());
297
generateLabelInstruction(TR::InstOpCode::JNE4, callNode, longReleaseSnippetLabel, cg());
298
generateLabelInstruction(TR::InstOpCode::label, callNode, longReleaseRestartLabel, cg());
299
300
TR_OutlinedInstructionsGenerator og(longReleaseSnippetLabel, callNode, cg());
301
auto helper = comp()->getSymRefTab()->findOrCreateReleaseVMAccessSymbolRef(comp()->getMethodSymbol());
302
generateImmSymInstruction(TR::InstOpCode::CALLImm4, callNode, (uintptr_t)helper->getMethodAddress(), helper, cg());
303
generateLabelInstruction(TR::InstOpCode::JMP4, callNode, longReleaseRestartLabel, cg());
304
og.endOutlinedInstructionSequence();
305
}
306
307
// Dispatch jni method directly.
308
//
309
TR::Instruction *instr = generateImmSymInstruction(
310
TR::InstOpCode::CALLImm4,
311
callNode,
312
(uintptr_t)resolvedMethodSymbol->getResolvedMethod()->startAddressForJNIMethod(comp()),
313
callNode->getSymbolReference(),
314
cg()
315
);
316
317
if (isJNIGCPoint)
318
instr->setNeedsGCMap((argSize<<14) | 0xFF00FFFF);
319
320
// memoize the call instruction, in order that we can register an assumption for this later on
321
cg()->getJNICallSites().push_front(new (trHeapMemory()) TR_Pair<TR_ResolvedMethod,TR::Instruction>(resolvedMethodSymbol->getResolvedMethod(), instr));
322
323
// To Do:: will need an aot relocation for this one at some point.
324
325
// Lay down a label for the frame push to reference.
326
//
327
generateLabelInstruction(TR::InstOpCode::label, callNode, returnAddrLabel, cg());
328
329
// Restore stack pointer
330
generateRegRegInstruction(TR::InstOpCode::MOV4RegReg, callNode, espReal, ediReal, cg());
331
cg()->stopUsingRegister(ediReal);
332
333
// Need to squirrel away the return value for some data types to avoid register
334
// conflicts with subsequent code to acquire vm access, etc.
335
//
336
// jni methods may not return a full register in some cases so need to get the declared
337
// type so that we sign and zero extend the narrower integer return types properly.
338
//
339
bool isUnsigned = resolvedMethod->returnTypeIsUnsigned();
340
bool isBoolean;
341
switch (resolvedMethod->returnType())
342
{
343
case TR::Int8:
344
isBoolean = comp()->getSymRefTab()->isReturnTypeBool(callSymRef);
345
if (isBoolean)
346
{
347
// For bool return type, must check whether value returned by
348
// JNI is zero (false) or non-zero (true) to yield Java result
349
generateRegRegInstruction(TR::InstOpCode::TEST1RegReg, callNode, eaxReal, eaxReal, cg());
350
generateRegInstruction(TR::InstOpCode::SETNE1Reg, callNode, eaxReal, cg());
351
}
352
generateRegRegInstruction((isUnsigned || isBoolean)
353
? TR::InstOpCode::MOVZXReg4Reg1 : TR::InstOpCode::MOVSXReg4Reg1,
354
callNode, ecxReal, eaxReal, cg());
355
break;
356
case TR::Int16:
357
generateRegRegInstruction(isUnsigned ? TR::InstOpCode::MOVZXReg4Reg2 : TR::InstOpCode::MOVSXReg4Reg2,
358
callNode, ecxReal, eaxReal, cg());
359
break;
360
case TR::Address:
361
case TR::Int64:
362
case TR::Int32:
363
generateRegRegInstruction(TR::InstOpCode::MOV4RegReg, callNode, ecxReal, eaxReal, cg());
364
break;
365
}
366
367
if (dropVMAccess)
368
{
369
// Re-acquire vm access.
370
//
371
generateMemImmInstruction(TR::InstOpCode::S4MemImm4,
372
callNode,
373
generateX86MemoryReference(ebpReal, offsetof(struct J9VMThread, inNative), cg()),
374
0,
375
cg());
376
377
#if !defined(J9VM_INTERP_ATOMIC_FREE_JNI_USES_FLUSH)
378
TR::MemoryReference *mr = generateX86MemoryReference(espReal, intptr_t(0), cg());
379
mr->setRequiresLockPrefix();
380
generateMemImmInstruction(TR::InstOpCode::OR4MemImms, callNode, mr, 0, cg());
381
#endif /* !J9VM_INTERP_ATOMIC_FREE_JNI_USES_FLUSH */
382
383
TR::LabelSymbol *longAcquireSnippetLabel = generateLabelSymbol(cg());
384
TR::LabelSymbol *longAcquireRestartLabel = generateLabelSymbol(cg());
385
386
static_assert(J9_PUBLIC_FLAGS_VM_ACCESS <= 0x7fffffff, "VM access bit must be immediate");
387
generateMemImmInstruction(TR::InstOpCode::CMP4MemImm4,
388
callNode,
389
generateX86MemoryReference(ebpReal, fej9->thisThreadGetPublicFlagsOffset(), cg()),
390
J9_PUBLIC_FLAGS_VM_ACCESS,
391
cg());
392
generateLabelInstruction(TR::InstOpCode::JNE4, callNode, longAcquireSnippetLabel, cg());
393
generateLabelInstruction(TR::InstOpCode::label, callNode, longAcquireRestartLabel, cg());
394
395
TR_OutlinedInstructionsGenerator og(longAcquireSnippetLabel, callNode, cg());
396
auto helper = comp()->getSymRefTab()->findOrCreateAcquireVMAccessSymbolRef(comp()->getMethodSymbol());
397
generateImmSymInstruction(TR::InstOpCode::CALLImm4, callNode, (uintptr_t)helper->getMethodAddress(), helper, cg());
398
generateLabelInstruction(TR::InstOpCode::JMP4, callNode, longAcquireRestartLabel, cg());
399
og.endOutlinedInstructionSequence();
400
}
401
402
if (TR::Address == resolvedMethod->returnType() && wrapRefs)
403
{
404
// Unless NULL, need to indirect once to get the real java reference
405
//
406
TR::LabelSymbol *tempLab = generateLabelSymbol(cg());
407
generateRegRegInstruction(TR::InstOpCode::TEST4RegReg, callNode, ecxReal, ecxReal, cg());
408
generateLabelInstruction(TR::InstOpCode::JE4, callNode, tempLab, cg());
409
generateRegMemInstruction(TR::InstOpCode::L4RegMem, callNode, ecxReal, generateX86MemoryReference(ecxReal, 0, cg()), cg());
410
generateLabelInstruction(TR::InstOpCode::label, callNode, tempLab, cg());
411
}
412
413
// Switch stacks back.
414
// First store out the machine sp into the vm thread. It has to be done as sometimes
415
// it gets tromped on by call backs.
416
//
417
generateMemRegInstruction(
418
TR::InstOpCode::S4MemReg,
419
callNode,
420
generateX86MemoryReference(ebpReal, fej9->thisThreadGetMachineSPOffset(), cg()),
421
espReal,
422
cg()
423
);
424
425
// Next load up the java sp so we have the callout frame on top of the java stack.
426
//
427
generateRegMemInstruction(
428
TR::InstOpCode::L4RegMem,
429
callNode,
430
espReal,
431
generateX86MemoryReference(ebpReal, fej9->thisThreadGetJavaSPOffset(), cg()),
432
cg()
433
);
434
435
if (createJNIFrame)
436
{
437
generateRegMemInstruction(
438
TR::InstOpCode::ADD4RegMem,
439
callNode,
440
espReal,
441
generateX86MemoryReference(ebpReal, fej9->thisThreadGetJavaLiteralsOffset(), cg()),
442
cg()
443
);
444
445
if (tearDownJNIFrame)
446
{
447
// Must check to see if the ref pool was used and clean them up if so--or we
448
// leave a bunch of pinned garbage behind that screws up the gc quality forever.
449
//
450
uint32_t flagValue = fej9->constJNIReferenceFrameAllocatedFlags();
451
TR::InstOpCode::Mnemonic op = flagValue <= 255 ? TR::InstOpCode::TEST1MemImm1 : TR::InstOpCode::TEST4MemImm4;
452
TR::LabelSymbol *refPoolSnippetLabel = generateLabelSymbol(cg());
453
TR::LabelSymbol *refPoolRestartLabel = generateLabelSymbol(cg());
454
generateMemImmInstruction(op, callNode, generateX86MemoryReference(espReal, fej9->constJNICallOutFrameFlagsOffset(), cg()), flagValue, cg());
455
generateLabelInstruction(TR::InstOpCode::JNE4, callNode, refPoolSnippetLabel, cg());
456
generateLabelInstruction(TR::InstOpCode::label, callNode, refPoolRestartLabel, cg());
457
458
TR_OutlinedInstructionsGenerator og(refPoolSnippetLabel, callNode, cg());
459
generateHelperCallInstruction(callNode, TR_IA32jitCollapseJNIReferenceFrame, NULL, cg());
460
generateLabelInstruction(TR::InstOpCode::JMP4, callNode, refPoolRestartLabel, cg());
461
og.endOutlinedInstructionSequence();
462
}
463
464
// Now set esp back to its previous value.
465
//
466
generateRegImmInstruction(TR::InstOpCode::ADD4RegImms, callNode, espReal, 20, cg());
467
}
468
469
// Get return registers set up before preserved regs are restored.
470
//
471
TR::Register *returnRegister = NULL;
472
switch (callNode->getDataType())
473
{
474
case TR::Int32:
475
case TR::Address:
476
returnRegister = ecxReal;
477
break;
478
case TR::Int64:
479
returnRegister = cg()->allocateRegisterPair(ecxReal, edxReal);
480
break;
481
482
// Current system linkage does not use XMM0 for floating point return, even if SSE is supported on the processor.
483
//
484
case TR::Float:
485
deps->addPostCondition(returnRegister = cg()->allocateSinglePrecisionRegister(TR_X87), TR::RealRegister::st0, cg());
486
break;
487
case TR::Double:
488
deps->addPostCondition(returnRegister = cg()->allocateRegister(TR_X87), TR::RealRegister::st0, cg());
489
break;
490
}
491
492
deps->stopAddingConditions();
493
494
if (checkExceptions)
495
{
496
// Check exceptions.
497
//
498
generateMemImmInstruction(
499
TR::InstOpCode::CMP4MemImms,
500
callNode,
501
generateX86MemoryReference(ebpReal, fej9->thisThreadGetCurrentExceptionOffset(), cg()),
502
0,
503
cg()
504
);
505
TR::LabelSymbol *snippetLabel = generateLabelSymbol(cg());
506
instr = generateLabelInstruction(TR::InstOpCode::JNE4, callNode, snippetLabel, cg());
507
instr->setNeedsGCMap((argSize<<14) | 0xFF00FFFF);
508
509
TR::Snippet *snippet = new (trHeapMemory()) TR::X86CheckFailureSnippet(
510
cg(),
511
cg()->symRefTab()->findOrCreateRuntimeHelper(TR_throwCurrentException),
512
snippetLabel,
513
instr,
514
callNode->getDataType() == TR::Float || callNode->getDataType() == TR::Double);
515
cg()->addSnippet(snippet);
516
}
517
518
// Restore VFP
519
generateVFPRestoreInstruction(vfpSave, callNode, cg());
520
generateLabelInstruction(TR::InstOpCode::label, callNode, endLabel, deps, cg());
521
522
// Stop using the killed registers that are not going to persist.
523
//
524
if (deps)
525
stopUsingKilledRegisters(deps, returnRegister);
526
527
// If the processor supports SSE, return floating-point values in XMM registers.
528
//
529
if (callNode->getOpCode().isFloat())
530
{
531
TR::MemoryReference *tempMR = cg()->machine()->getDummyLocalMR(TR::Float);
532
generateFPMemRegInstruction(TR::InstOpCode::FSTPMemReg, callNode, tempMR, returnRegister, cg());
533
returnRegister = cg()->allocateSinglePrecisionRegister(TR_FPR);
534
generateRegMemInstruction(TR::InstOpCode::MOVSSRegMem, callNode, returnRegister, generateX86MemoryReference(*tempMR, 0, cg()), cg());
535
}
536
else if (callNode->getOpCode().isDouble())
537
{
538
TR::MemoryReference *tempMR = cg()->machine()->getDummyLocalMR(TR::Double);
539
generateFPMemRegInstruction(TR::InstOpCode::DSTPMemReg, callNode, tempMR, returnRegister, cg());
540
returnRegister = cg()->allocateRegister(TR_FPR);
541
generateRegMemInstruction(cg()->getXMMDoubleLoadOpCode(), callNode, returnRegister, generateX86MemoryReference(*tempMR, 0, cg()), cg());
542
}
543
544
if (cg()->enableRegisterAssociations())
545
associatePreservedRegisters(deps, returnRegister);
546
547
return returnRegister;
548
}
549
550
#endif
551
552