Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/arm/codegen/ARMJNILinkage.cpp
6004 views
1
/*******************************************************************************
2
* Copyright (c) 2016, 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/ARMJNILinkage.hpp"
24
25
#include "arm/codegen/ARMInstruction.hpp"
26
#include "codegen/CallSnippet.hpp"
27
#include "codegen/CodeGenerator.hpp"
28
#include "codegen/CodeGeneratorUtils.hpp"
29
#include "codegen/GCStackAtlas.hpp"
30
#include "codegen/GCStackMap.hpp"
31
#include "codegen/GenerateInstructions.hpp"
32
#include "codegen/Linkage_inlines.hpp"
33
#include "codegen/Machine.hpp"
34
#include "codegen/RealRegister.hpp"
35
#include "codegen/Register.hpp"
36
#include "codegen/RegisterPair.hpp"
37
#include "codegen/StackCheckFailureSnippet.hpp"
38
#include "env/CompilerEnv.hpp"
39
#include "env/J2IThunk.hpp"
40
#include "env/VMJ9.h"
41
#include "env/jittypes.h"
42
#include "il/LabelSymbol.hpp"
43
#include "il/MethodSymbol.hpp"
44
#include "il/Node.hpp"
45
#include "il/Node_inlines.hpp"
46
#include "il/RegisterMappedSymbol.hpp"
47
#include "il/ResolvedMethodSymbol.hpp"
48
#include "il/StaticSymbol.hpp"
49
#include "il/Symbol.hpp"
50
#include "il/TreeTop.hpp"
51
#include "il/TreeTop_inlines.hpp"
52
53
#define LOCK_R14
54
55
// TODO: Merge with TR::ARMLinkageProperties
56
static TR::RealRegister::RegNum _singleArgumentRegisters[] =
57
{
58
TR::RealRegister::fs0,
59
TR::RealRegister::fs1,
60
TR::RealRegister::fs2,
61
TR::RealRegister::fs3,
62
TR::RealRegister::fs4,
63
TR::RealRegister::fs5,
64
TR::RealRegister::fs6,
65
TR::RealRegister::fs7,
66
TR::RealRegister::fs8,
67
TR::RealRegister::fs9,
68
TR::RealRegister::fs10,
69
TR::RealRegister::fs11,
70
TR::RealRegister::fs12,
71
TR::RealRegister::fs13,
72
TR::RealRegister::fs14,
73
TR::RealRegister::fs15
74
};
75
76
J9::ARM::JNILinkage::JNILinkage(TR::CodeGenerator *cg)
77
: J9::ARM::PrivateLinkage(cg)
78
{
79
//Copy out SystemLinkage properties. Assumes no objects in TR::ARMLinkageProperties.
80
TR::Linkage *sysLinkage = cg->getLinkage(TR_System);
81
const TR::ARMLinkageProperties& sysLinkageProperties = sysLinkage->getProperties();
82
83
_properties = sysLinkageProperties;
84
85
//Set preservedRegisterMapForGC to PrivateLinkage properties.
86
TR::Linkage *privateLinkage = cg->getLinkage(TR_Private);
87
const TR::ARMLinkageProperties& privateLinkageProperties = privateLinkage->getProperties();
88
89
_properties._preservedRegisterMapForGC = privateLinkageProperties.getPreservedRegisterMapForGC();
90
91
}
92
93
int32_t J9::ARM::JNILinkage::buildArgs(TR::Node *callNode,
94
TR::RegisterDependencyConditions *dependencies,
95
TR::Register* &vftReg,
96
bool isVirtual)
97
{
98
TR_ASSERT(0, "Should call J9::ARM::JNILinkage::buildJNIArgs instead.");
99
return 0;
100
}
101
102
TR::Register *J9::ARM::JNILinkage::buildIndirectDispatch(TR::Node *callNode)
103
{
104
TR_ASSERT(0, "Calling J9::ARM::JNILinkage::buildIndirectDispatch does not make sense.");
105
return NULL;
106
}
107
108
void J9::ARM::JNILinkage::buildVirtualDispatch(TR::Node *callNode,
109
TR::RegisterDependencyConditions *dependencies,
110
TR::RegisterDependencyConditions *postDeps,
111
TR::Register *vftReg,
112
uint32_t sizeOfArguments)
113
{
114
TR_ASSERT(0, "Calling J9::ARM::JNILinkage::buildVirtualDispatch does not make sense.");
115
}
116
117
TR::ARMLinkageProperties& J9::ARM::JNILinkage::getProperties()
118
{
119
return _properties;
120
}
121
122
#if defined(__VFP_FP__) && !defined(__SOFTFP__)
123
TR::Register *J9::ARM::JNILinkage::pushFloatArgForJNI(TR::Node *child)
124
{
125
// if (isSmall()) return 0;
126
127
TR::Register *pushRegister = cg()->evaluate(child);
128
child->setRegister(pushRegister);
129
child->decReferenceCount();
130
if (pushRegister->getKind() == TR_GPR)
131
{
132
TR::Register *trgReg = cg()->allocateSinglePrecisionRegister();
133
generateTrg1Src1Instruction(cg(), TR::InstOpCode::fmsr, child, trgReg, pushRegister);
134
return trgReg;
135
}
136
137
return pushRegister;
138
}
139
140
TR::Register *J9::ARM::JNILinkage::pushDoubleArgForJNI(TR::Node *child)
141
{
142
// if (isSmall()) return 0;
143
144
TR::Register *pushRegister = cg()->evaluate(child);
145
child->setRegister(pushRegister);
146
child->decReferenceCount();
147
if (pushRegister->getKind() == TR_GPR)
148
{
149
TR::Register *trgReg = cg()->allocateRegister(TR_FPR);
150
TR::RegisterPair *pair = pushRegister->getRegisterPair();
151
generateTrg1Src2Instruction(cg(), TR::InstOpCode::fmdrr, child, trgReg, pair->getLowOrder(), pair->getHighOrder());
152
return trgReg;
153
}
154
return pushRegister;
155
}
156
#endif
157
158
TR::MemoryReference *J9::ARM::JNILinkage::getOutgoingArgumentMemRef(int32_t totalSize,
159
int32_t offset,
160
TR::Register *argReg,
161
TR::InstOpCode::Mnemonic opCode,
162
TR::ARMMemoryArgument &memArg)
163
{
164
/* totalSize does not matter */
165
#ifdef DEBUG_ARM_LINKAGE
166
printf("JNI: offset %d\n", offset); fflush(stdout);
167
#endif
168
const TR::ARMLinkageProperties &jniLinkageProperties = getProperties();
169
int32_t spOffset = offset + getOffsetToFirstParm();
170
TR::RealRegister *sp = cg()->machine()->getRealRegister(jniLinkageProperties.getStackPointerRegister());
171
TR::MemoryReference *result = new (trHeapMemory()) TR::MemoryReference(sp, spOffset, cg());
172
memArg.argRegister = argReg;
173
memArg.argMemory = result;
174
memArg.opCode = opCode;
175
return result;
176
}
177
178
int32_t J9::ARM::JNILinkage::buildJNIArgs(TR::Node *callNode,
179
TR::RegisterDependencyConditions *dependencies,
180
TR::Register* &vftReg,
181
bool passReceiver,
182
bool passEnvArg)
183
{
184
TR::CodeGenerator *codeGen = cg();
185
TR::Compilation *comp = codeGen->comp();
186
TR::ARMMemoryArgument *pushToMemory = NULL;
187
const TR::ARMLinkageProperties &jniLinkageProperties = getProperties();
188
189
bool bigEndian = comp->target().cpu.isBigEndian();
190
int32_t i;
191
uint32_t numIntegerArgRegIndex = 0;
192
uint32_t numFloatArgRegIndex = 0;
193
uint32_t numDoubleArgRegIndex = 0;
194
uint32_t numSingleArgRegIndex = 0; // if nonzero, use the second half of VFP register
195
uint32_t numMemArgs = 0;
196
uint32_t stackOffset = 0;
197
uint32_t numIntArgRegs = jniLinkageProperties.getNumIntArgRegs();
198
uint32_t numFloatArgRegs = jniLinkageProperties.getNumFloatArgRegs();
199
bool isEABI = comp->target().isEABI();
200
uint32_t firstArgumentChild = callNode->getFirstArgumentIndex();
201
TR::DataType callNodeDataType = callNode->getDataType();
202
TR::DataType resType = callNode->getType();
203
TR::MethodSymbol *callSymbol = callNode->getSymbol()->castToMethodSymbol();
204
205
if (passEnvArg)
206
numIntegerArgRegIndex = 1;
207
208
if (!passReceiver)
209
{
210
// Evaluate as usual if necessary, but don't actually pass it to the callee
211
TR::Node *firstArgChild = callNode->getChild(firstArgumentChild);
212
if (firstArgChild->getReferenceCount() > 1)
213
{
214
switch (firstArgChild->getDataType())
215
{
216
case TR::Int32:
217
pushIntegerWordArg(firstArgChild);
218
break;
219
case TR::Int64:
220
pushLongArg(firstArgChild);
221
break;
222
case TR::Address:
223
pushAddressArg(firstArgChild);
224
break;
225
default:
226
TR_ASSERT( false, "Unexpected first child type");
227
}
228
}
229
else
230
codeGen->recursivelyDecReferenceCount(firstArgChild);
231
firstArgumentChild += 1;
232
}
233
234
/* Step 1 - figure out how many arguments are going to be spilled to memory i.e. not in registers */
235
for (i = firstArgumentChild; i < callNode->getNumChildren(); i++)
236
{
237
switch (callNode->getChild(i)->getDataType())
238
{
239
case TR::Int8:
240
case TR::Int16:
241
case TR::Int32:
242
case TR::Address:
243
#if !defined(__ARM_PCS_VFP)
244
case TR::Float:
245
#endif
246
if (numIntegerArgRegIndex >= numIntArgRegs)
247
{
248
numMemArgs++;
249
stackOffset += 4;
250
}
251
numIntegerArgRegIndex++;
252
break;
253
case TR::Int64:
254
#if !defined(__ARM_PCS_VFP)
255
case TR::Double:
256
#endif
257
if (isEABI)
258
{
259
// The MVL CEE 3.0 system linkage requires that an unaligned
260
// long argument consume an extra slot of padding
261
if (numIntegerArgRegIndex + 1 >= numIntArgRegs)
262
{
263
/* if numIntegerArgRegIndex >= numIntArgReg - 1, we do not need to care about the register slot padding. */
264
numIntegerArgRegIndex += 2;
265
numMemArgs += 2;
266
/* but we need to care about the stack alignment instead. */
267
stackOffset = (stackOffset + 12) & (~7);
268
}
269
else
270
{
271
if (numIntegerArgRegIndex & 1)
272
numIntegerArgRegIndex += 3; // an unaligned long argument consume an extra slot of padding
273
else
274
numIntegerArgRegIndex += 2;
275
}
276
}
277
else
278
{
279
if (numIntegerArgRegIndex + 1 == numIntArgRegs)
280
{
281
numMemArgs++;
282
stackOffset += 4;
283
}
284
else if (numIntegerArgRegIndex + 1 > numIntArgRegs)
285
{
286
numMemArgs += 2;
287
stackOffset += 8;
288
}
289
290
numIntegerArgRegIndex += 2;
291
}
292
break;
293
#if defined(__ARM_PCS_VFP) // -mfloat-abi=hard
294
case TR::Float:
295
if ((numFloatArgRegIndex < numFloatArgRegs) || (numFloatArgRegIndex == numFloatArgRegs && numSingleArgRegIndex != 0))
296
{
297
if (numSingleArgRegIndex != 0)
298
{
299
numSingleArgRegIndex = 0;
300
}
301
else
302
{
303
numSingleArgRegIndex = numFloatArgRegIndex * 2 + 1;
304
numFloatArgRegIndex++;
305
}
306
}
307
else
308
{
309
numMemArgs++;
310
stackOffset += 4;
311
312
numFloatArgRegIndex++;
313
if (numSingleArgRegIndex != 0)
314
{
315
numSingleArgRegIndex = 0;
316
}
317
}
318
break;
319
case TR::Double:
320
if (isEABI)
321
{
322
// The MVL CEE 3.0 system linkage requires that an unaligned
323
// long argument consume an extra slot of padding
324
// A VFP register can hold 64bit double value.
325
if (numFloatArgRegIndex >= numFloatArgRegs)
326
{
327
numMemArgs++;
328
/* 8byte stack alignment. */
329
stackOffset = (stackOffset + 12) & (~7);
330
}
331
}
332
else
333
{
334
if (numFloatArgRegIndex >= numFloatArgRegs)
335
{
336
numMemArgs++;
337
stackOffset += 8;
338
}
339
}
340
numFloatArgRegIndex++;
341
break;
342
#endif // ifndef __VFP_FP__
343
}
344
}
345
346
#ifdef DEBUG_ARM_LINKAGE
347
// const char *sig = callNode->getSymbol()->getResolvedMethodSymbol()->signature();
348
const char *sig = "CALL";
349
printf("%s: numIntegerArgRegIndex %d numMemArgs %d\n", sig, numIntegerArgRegIndex, numMemArgs); fflush(stdout);
350
#endif
351
352
353
int32_t numStackParmSlots = 0;
354
// From here, down, all stack memory allocations will expire / die when the function returns.
355
TR::StackMemoryRegion stackMemoryRegion(*trMemory());
356
if (numMemArgs > 0)
357
{
358
359
pushToMemory = new(trStackMemory()) TR::ARMMemoryArgument[numMemArgs];
360
361
// For direct-to-JNI calls, instead of pushing
362
// arguments, buy the necessary stack slots up front.
363
// On EABI, keep the C stack 8-byte aligned on entry to native callee.
364
numStackParmSlots = (isEABI ? ((stackOffset + 4) & (~7)) : stackOffset);
365
#ifdef DEBUG_ARM_LINKAGE
366
printf("subtracting %d slots from SP\n", numStackParmSlots); fflush(stdout);
367
#endif
368
TR::RealRegister *sp = codeGen->machine()->getRealRegister(jniLinkageProperties.getStackPointerRegister());
369
uint32_t base, rotate;
370
if (constantIsImmed8r(numStackParmSlots, &base, &rotate))
371
{
372
generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::sub, callNode, sp, sp, base, rotate);
373
}
374
else
375
{
376
TR::Register *tmpReg = codeGen->allocateRegister();
377
armLoadConstant(callNode, numStackParmSlots, tmpReg, codeGen);
378
generateTrg1Src2Instruction(codeGen, TR::InstOpCode::sub, callNode, sp, sp, tmpReg);
379
codeGen->stopUsingRegister(tmpReg);
380
}
381
}
382
383
if (passEnvArg)
384
numIntegerArgRegIndex = 1;
385
386
numFloatArgRegIndex = 0;
387
numSingleArgRegIndex = 0;
388
stackOffset = 0;
389
390
int32_t memArg = 0;
391
for (i = firstArgumentChild; i < callNode->getNumChildren(); i++)
392
{
393
TR::Node *child = callNode->getChild(i);
394
TR::DataType childType = child->getDataType();
395
TR::Register *reg;
396
TR::Register *tempReg;
397
TR::MemoryReference *tempMR;
398
399
switch (childType)
400
{
401
case TR::Int8:
402
case TR::Int16:
403
case TR::Int32:
404
case TR::Address: // have to do something for GC maps here
405
#if !defined(__ARM_PCS_VFP)
406
case TR::Float:
407
#endif
408
if (childType == TR::Address)
409
reg = pushJNIReferenceArg(child);
410
else
411
reg = pushIntegerWordArg(child);
412
413
if (numIntegerArgRegIndex < numIntArgRegs)
414
{
415
if ((childType != TR::Address) && !cg()->canClobberNodesRegister(child, 0))
416
{
417
/* If the reg is shared by another node, we copy it to tempReg, so that the reg is not reused after returning the call. */
418
if (reg->containsCollectedReference())
419
tempReg = codeGen->allocateCollectedReferenceRegister();
420
else
421
tempReg = codeGen->allocateRegister();
422
generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, child, tempReg, reg);
423
reg = tempReg;
424
}
425
if (numIntegerArgRegIndex == 0 &&
426
(resType.isAddress() || resType.isInt32() || resType.isInt64()))
427
{
428
TR::Register *resultReg;
429
if (resType.isAddress())
430
resultReg = codeGen->allocateCollectedReferenceRegister();
431
else
432
resultReg = codeGen->allocateRegister();
433
dependencies->addPreCondition(reg, TR::RealRegister::gr0);
434
dependencies->addPostCondition(resultReg, TR::RealRegister::gr0);
435
}
436
else if (numIntegerArgRegIndex == 1 && resType.isInt64())
437
{
438
TR::Register *resultReg = codeGen->allocateRegister();
439
dependencies->addPreCondition(reg, TR::RealRegister::gr1);
440
dependencies->addPostCondition(resultReg, TR::RealRegister::gr1);
441
}
442
else
443
{
444
TR::addDependency(dependencies, reg, jniLinkageProperties.getIntegerArgumentRegister(numIntegerArgRegIndex), TR_GPR, codeGen);
445
}
446
}
447
else
448
{
449
#ifdef DEBUG_ARM_LINKAGE
450
printf("pushing 32-bit arg %d %d\n", numIntegerArgRegIndex, memArg); fflush(stdout);
451
#endif
452
tempMR = getOutgoingArgumentMemRef(0, stackOffset, reg, TR::InstOpCode::str, pushToMemory[memArg++]);
453
stackOffset += 4;
454
}
455
numIntegerArgRegIndex++;
456
break;
457
case TR::Int64:
458
#if !defined(__ARM_PCS_VFP)
459
case TR::Double:
460
#endif
461
if (isEABI)
462
{
463
if (numIntegerArgRegIndex & 1)
464
{
465
#ifdef DEBUG_ARM_LINKAGE
466
printf("skipping one argument slot\n"); fflush(stdout);
467
#endif
468
numIntegerArgRegIndex++;
469
}
470
}
471
reg = pushLongArg(child);
472
473
if (numIntegerArgRegIndex < numIntArgRegs)
474
{
475
if (!cg()->canClobberNodesRegister(child, 0))
476
{
477
tempReg = codeGen->allocateRegister();
478
479
if (bigEndian)
480
{
481
generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, child, tempReg, reg->getRegisterPair()->getHighOrder());
482
reg = codeGen->allocateRegisterPair(reg->getRegisterPair()->getLowOrder(), tempReg);
483
}
484
else
485
{
486
generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, child, tempReg, reg->getRegisterPair()->getLowOrder());
487
reg = codeGen->allocateRegisterPair(tempReg, reg->getRegisterPair()->getHighOrder());
488
}
489
}
490
491
dependencies->addPreCondition(bigEndian ? reg->getRegisterPair()->getHighOrder() : reg->getRegisterPair()->getLowOrder(), jniLinkageProperties.getIntegerArgumentRegister(numIntegerArgRegIndex));
492
if ((numIntegerArgRegIndex == 0) && resType.isAddress())
493
dependencies->addPostCondition(codeGen->allocateCollectedReferenceRegister(), TR::RealRegister::gr0);
494
else
495
dependencies->addPostCondition(codeGen->allocateRegister(), jniLinkageProperties.getIntegerArgumentRegister(numIntegerArgRegIndex));
496
497
if (numIntegerArgRegIndex + 1 < numIntArgRegs)
498
{
499
if (!cg()->canClobberNodesRegister(child, 0))
500
{
501
tempReg = codeGen->allocateRegister();
502
if (bigEndian)
503
{
504
generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, child, tempReg, reg->getRegisterPair()->getLowOrder());
505
reg->getRegisterPair()->setLowOrder(tempReg, codeGen);
506
}
507
else
508
{
509
generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, child, tempReg, reg->getRegisterPair()->getHighOrder());
510
reg->getRegisterPair()->setHighOrder(tempReg, codeGen);
511
}
512
}
513
dependencies->addPreCondition(bigEndian ? reg->getRegisterPair()->getLowOrder() : reg->getRegisterPair()->getHighOrder(), jniLinkageProperties.getIntegerArgumentRegister(numIntegerArgRegIndex + 1));
514
dependencies->addPostCondition(codeGen->allocateRegister(), jniLinkageProperties.getIntegerArgumentRegister(numIntegerArgRegIndex + 1));
515
}
516
else
517
{
518
#ifdef DEBUG_ARM_LINKAGE
519
printf("pushing %s word of 64-bit arg %d %d\n", bigEndian ? "low" : "high", numIntegerArgRegIndex, memArg); fflush(stdout);
520
#endif
521
tempMR = getOutgoingArgumentMemRef(0, stackOffset, bigEndian ? reg->getRegisterPair()->getLowOrder() : reg->getRegisterPair()->getHighOrder(), TR::InstOpCode::str, pushToMemory[memArg++]);
522
stackOffset += 4;
523
}
524
}
525
else
526
{
527
#ifdef DEBUG_ARM_LINKAGE
528
printf("pushing 64-bit JNI arg %d %d %d\n", numIntegerArgs, memArg, totalSize); fflush(stdout);
529
#endif
530
if (isEABI)
531
stackOffset = (stackOffset + 4) & (~7);
532
tempMR = getOutgoingArgumentMemRef(0, stackOffset, bigEndian ? reg->getRegisterPair()->getHighOrder() : reg->getRegisterPair()->getLowOrder(), TR::InstOpCode::str, pushToMemory[memArg++]);
533
tempMR = getOutgoingArgumentMemRef(0, stackOffset + 4, bigEndian ? reg->getRegisterPair()->getLowOrder() : reg->getRegisterPair()->getHighOrder(), TR::InstOpCode::str, pushToMemory[memArg++]);
534
stackOffset += 8;
535
}
536
numIntegerArgRegIndex += 2;
537
break;
538
#if defined(__ARM_PCS_VFP) // -mfloat-abi=hard
539
case TR::Float:
540
reg = pushFloatArgForJNI(child);
541
if ((numFloatArgRegIndex < numFloatArgRegs) || (numFloatArgRegIndex == numFloatArgRegs && numSingleArgRegIndex != 0))
542
{
543
if (!cg()->canClobberNodesRegister(child, 0))
544
{
545
tempReg = codeGen->allocateSinglePrecisionRegister();
546
generateTrg1Src1Instruction(codeGen, TR::InstOpCode::fcpys, child, tempReg, reg);
547
reg = tempReg;
548
}
549
if ((numFloatArgRegIndex == 0) && resType.isFloatingPoint())
550
{
551
TR::Register *resultReg;
552
if (resType.getDataType() == TR::Float)
553
resultReg = codeGen->allocateSinglePrecisionRegister();
554
else
555
resultReg = codeGen->allocateRegister(TR_FPR);
556
557
dependencies->addPreCondition(reg, TR::RealRegister::fs0);
558
dependencies->addPostCondition(resultReg, TR::RealRegister::fp0);
559
}
560
else
561
{
562
uint32_t regIdx = (numSingleArgRegIndex != 0) ? numSingleArgRegIndex : numFloatArgRegIndex * 2;
563
dependencies->addPreCondition(reg, _singleArgumentRegisters[regIdx]);
564
if (numSingleArgRegIndex == 0)
565
{
566
dependencies->addPostCondition(reg, jniLinkageProperties.getFloatArgumentRegister(numFloatArgRegIndex));
567
}
568
}
569
570
if (numSingleArgRegIndex != 0)
571
{
572
numSingleArgRegIndex = 0;
573
}
574
else
575
{
576
numSingleArgRegIndex = numFloatArgRegIndex * 2 + 1;
577
numFloatArgRegIndex++;
578
}
579
}
580
else
581
{
582
tempMR = getOutgoingArgumentMemRef(0, stackOffset, reg, TR::InstOpCode::fsts, pushToMemory[memArg++]);
583
stackOffset += 4;
584
585
numFloatArgRegIndex++;
586
if (numSingleArgRegIndex != 0)
587
{
588
numSingleArgRegIndex = 0;
589
}
590
}
591
break;
592
case TR::Double:
593
reg = pushDoubleArgForJNI(child);
594
if (numFloatArgRegIndex < numFloatArgRegs)
595
{
596
if (!cg()->canClobberNodesRegister(child, 0))
597
{
598
tempReg = cg()->allocateRegister(TR_FPR);
599
generateTrg1Src1Instruction(codeGen, TR::InstOpCode::fcpyd, child, tempReg, reg);
600
reg = tempReg;
601
}
602
if ((numFloatArgRegIndex == 0) && resType.isFloatingPoint())
603
{
604
TR::Register *resultReg;
605
if (resType.getDataType() == TR::Float)
606
resultReg = codeGen->allocateSinglePrecisionRegister();
607
else
608
resultReg = codeGen->allocateRegister(TR_FPR);
609
610
dependencies->addPreCondition(reg, TR::RealRegister::fp0);
611
dependencies->addPostCondition(resultReg, TR::RealRegister::fp0);
612
}
613
else
614
TR::addDependency(dependencies, reg, jniLinkageProperties.getFloatArgumentRegister(numFloatArgRegIndex), TR_FPR, codeGen);
615
}
616
else
617
{
618
if (isEABI)
619
stackOffset = (stackOffset + 4) & (~7);
620
tempMR = getOutgoingArgumentMemRef(0, stackOffset, reg, TR::InstOpCode::fstd, pushToMemory[memArg++]);
621
stackOffset += 8;
622
}
623
numFloatArgRegIndex++;
624
break;
625
#endif
626
}
627
}
628
629
for (i = 0; i < jniLinkageProperties.getNumIntArgRegs(); i++)
630
{
631
TR::RealRegister::RegNum realReg = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::gr0 + i);
632
if (passEnvArg && (realReg == TR::RealRegister::gr0))
633
continue;
634
if (!dependencies->searchPreConditionRegister(realReg))
635
{
636
if (realReg == jniLinkageProperties.getIntegerArgumentRegister(0) && resType.isAddress())
637
{
638
dependencies->addPreCondition(codeGen->allocateRegister(), TR::RealRegister::gr0);
639
dependencies->addPostCondition(codeGen->allocateCollectedReferenceRegister(), TR::RealRegister::gr0);
640
}
641
else if ((realReg == TR::RealRegister::gr1) && resType.isInt64())
642
{
643
dependencies->addPreCondition(codeGen->allocateRegister(), TR::RealRegister::gr1);
644
dependencies->addPostCondition(codeGen->allocateRegister(), TR::RealRegister::gr1);
645
}
646
else
647
{
648
TR::addDependency(dependencies, NULL, realReg, TR_GPR, codeGen);
649
}
650
}
651
}
652
653
/* d0-d8 are argument registers and not preserved across the call. */
654
for (i = 0; i < jniLinkageProperties.getNumFloatArgRegs(); i++)
655
{
656
TR::RealRegister::RegNum realReg = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fp0 + i);
657
if (!dependencies->searchPreConditionRegister(realReg))
658
{
659
TR::RealRegister::RegNum singleReg1, singleReg2;
660
singleReg1 = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fs0 + i*2);
661
singleReg2 = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fs0 + i*2 + 1);
662
if (!dependencies->searchPreConditionRegister(singleReg1))
663
{
664
TR_ASSERT(!dependencies->searchPreConditionRegister(singleReg2), "Wrong dependency for single precision register.\n");
665
if (realReg == jniLinkageProperties.getFloatArgumentRegister(0) && (resType.getDataType() == TR::Float))
666
{
667
dependencies->addPreCondition(codeGen->allocateRegister(TR_FPR), TR::RealRegister::fp0);
668
dependencies->addPostCondition(codeGen->allocateSinglePrecisionRegister(), TR::RealRegister::fp0);
669
}
670
else
671
{
672
TR::addDependency(dependencies, NULL, realReg, TR_FPR, codeGen);
673
}
674
}
675
}
676
}
677
678
// add dependencies for other volatile registers; for virtual calls,
679
// dependencies on gr11 and gr14 have already been added above
680
#ifndef LOCK_R14
681
TR::addDependency(dependencies, NULL, TR::RealRegister::gr14, TR_GPR, codeGen);
682
#endif
683
684
for (i = 0; i < numMemArgs; i++)
685
{
686
#ifdef DEBUG_ARM_LINKAGE
687
printf("pushing mem arg %d of %d (in reg %x) to [sp + %d]... ", i, numMemArgs, pushToMemory[i].argRegister, pushToMemory[i].argMemory->getOffset()); fflush(stdout);
688
#endif
689
TR::Register *aReg = pushToMemory[i].argRegister;
690
generateMemSrc1Instruction(codeGen,
691
pushToMemory[i].opCode,
692
callNode,
693
pushToMemory[i].argMemory,
694
pushToMemory[i].argRegister);
695
codeGen->stopUsingRegister(aReg);
696
#ifdef DEBUG_ARM_LINKAGE
697
printf("done\n"); fflush(stdout);
698
#endif
699
}
700
//Returns the size of parameter buffers allocated on stack
701
return numStackParmSlots;
702
703
}
704
705
706
TR::Register *J9::ARM::JNILinkage::buildDirectDispatch(TR::Node *callNode)
707
{
708
TR::CodeGenerator *codeGen = cg();
709
const TR::ARMLinkageProperties &jniLinkageProperties = getProperties();
710
TR::Linkage *privateLinkage = codeGen->getLinkage(TR_Private);
711
const TR::ARMLinkageProperties &privateLinkageProperties = privateLinkage->getProperties();
712
713
TR::RegisterDependencyConditions *deps =
714
new (trHeapMemory()) TR::RegisterDependencyConditions(jniLinkageProperties.getNumberOfDependencyGPRegisters() + jniLinkageProperties.getNumFloatArgRegs()*2,
715
jniLinkageProperties.getNumberOfDependencyGPRegisters() + jniLinkageProperties.getNumFloatArgRegs()*2, trMemory());
716
717
TR::SymbolReference *callSymRef = callNode->getSymbolReference();
718
TR::ResolvedMethodSymbol *calleeSym = callSymRef->getSymbol()->castToResolvedMethodSymbol();
719
TR_ResolvedMethod *resolvedMethod = calleeSym->getResolvedMethod();
720
721
codeGen->machine()->setLinkRegisterKilled(true);
722
codeGen->setHasCall();
723
724
// buildArgs() will set up dependencies for the volatile registers, except gr0.
725
TR::Register* vftReg = NULL;
726
int32_t spSize = buildJNIArgs(callNode, deps, vftReg, true, true);
727
728
// kill all values in non-volatile registers so that the
729
// values will be in a stack frame in case GC looks for them
730
TR::addDependency(deps, NULL, TR::RealRegister::gr4, TR_GPR, codeGen);
731
TR::addDependency(deps, NULL, TR::RealRegister::gr5, TR_GPR, codeGen);
732
TR::addDependency(deps, NULL, TR::RealRegister::gr6, TR_GPR, codeGen);
733
TR::addDependency(deps, NULL, TR::RealRegister::gr9, TR_GPR, codeGen);
734
TR::addDependency(deps, NULL, TR::RealRegister::gr10, TR_GPR, codeGen);
735
TR::addDependency(deps, NULL, TR::RealRegister::gr11, TR_GPR, codeGen);
736
737
// set up dependency for the return register
738
TR::Register *gr0Reg = deps->searchPreConditionRegister(TR::RealRegister::gr0);
739
TR::Register *returnRegister = NULL;
740
TR::Register *lowReg = NULL, *highReg;
741
742
switch (callNode->getOpCodeValue())
743
{
744
case TR::icall:
745
case TR::acall:
746
#if !defined(__VFP_FP__) || defined(__SOFTFP__)
747
case TR::fcall:
748
#endif
749
if (callNode->getDataType() == TR::Address)
750
{
751
if (!gr0Reg)
752
{
753
gr0Reg = codeGen->allocateRegister();
754
returnRegister = codeGen->allocateCollectedReferenceRegister();
755
deps->addPreCondition(gr0Reg, TR::RealRegister::gr0);
756
deps->addPostCondition(returnRegister, TR::RealRegister::gr0);
757
}
758
else
759
{
760
returnRegister = deps->searchPostConditionRegister(TR::RealRegister::gr0);
761
}
762
}
763
else
764
{
765
if (!gr0Reg)
766
{
767
gr0Reg = codeGen->allocateRegister();
768
returnRegister = gr0Reg;
769
TR::addDependency(deps, gr0Reg, TR::RealRegister::gr0, TR_GPR, codeGen);
770
}
771
else
772
{
773
returnRegister = deps->searchPostConditionRegister(TR::RealRegister::gr0);
774
}
775
}
776
break;
777
case TR::lcall:
778
#if !defined(__VFP_FP__) || defined(__SOFTFP__)
779
case TR::dcall:
780
#endif
781
{
782
if(codeGen->comp()->target().cpu.isBigEndian())
783
{
784
if (!gr0Reg)
785
{
786
gr0Reg = codeGen->allocateRegister();
787
TR::addDependency(deps, gr0Reg, TR::RealRegister::gr0, TR_GPR, codeGen);
788
highReg = gr0Reg;
789
}
790
else
791
{
792
highReg = deps->searchPostConditionRegister(TR::RealRegister::gr0);
793
}
794
lowReg = deps->searchPostConditionRegister(TR::RealRegister::gr1);
795
}
796
else
797
{
798
if (!gr0Reg)
799
{
800
gr0Reg = codeGen->allocateRegister();
801
TR::addDependency(deps, gr0Reg, TR::RealRegister::gr0, TR_GPR, codeGen);
802
lowReg = gr0Reg;
803
}
804
else
805
{
806
lowReg = deps->searchPostConditionRegister(TR::RealRegister::gr0);
807
}
808
highReg = deps->searchPostConditionRegister(TR::RealRegister::gr1);
809
}
810
returnRegister = codeGen->allocateRegisterPair(lowReg, highReg);
811
break;
812
}
813
#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
814
case TR::fcall:
815
case TR::dcall:
816
returnRegister = deps->searchPostConditionRegister(jniLinkageProperties.getFloatReturnRegister(0));
817
if (!gr0Reg)
818
{
819
gr0Reg = codeGen->allocateRegister();
820
TR::addDependency(deps, gr0Reg, TR::RealRegister::gr0, TR_GPR, codeGen);
821
}
822
break;
823
#endif
824
case TR::call:
825
if (!gr0Reg)
826
{
827
gr0Reg = codeGen->allocateRegister();
828
TR::addDependency(deps, gr0Reg, TR::RealRegister::gr0, TR_GPR, codeGen);
829
}
830
returnRegister = NULL;
831
break;
832
default:
833
if (!gr0Reg)
834
{
835
gr0Reg = codeGen->allocateRegister();
836
TR::addDependency(deps, gr0Reg, TR::RealRegister::gr0, TR_GPR, codeGen);
837
}
838
returnRegister = NULL;
839
TR_ASSERT(0, "Unknown direct call opode.\n");
840
}
841
842
deps->stopAddingConditions();
843
844
// build stack frame on the Java stack
845
TR::MemoryReference *tempMR;
846
847
TR::Machine *machine = codeGen->machine();
848
TR::RealRegister *metaReg = codeGen->getMethodMetaDataRegister();
849
TR::RealRegister *stackPtr = machine->getRealRegister(privateLinkageProperties.getStackPointerRegister());//JavaSP
850
TR::RealRegister *instrPtr = machine->getRealRegister(TR::RealRegister::gr15);
851
TR::RealRegister *gr13Reg = machine->getRealRegister(TR::RealRegister::gr13);
852
TR::Register *gr4Reg = deps->searchPreConditionRegister(TR::RealRegister::gr4);
853
TR::Register *gr5Reg = deps->searchPreConditionRegister(TR::RealRegister::gr5);
854
855
// Force spilling the volatile FPRs
856
int32_t i;
857
TR::LabelSymbol *spillLabel = generateLabelSymbol(codeGen);
858
TR::RegisterDependencyConditions *spillDeps = new (trHeapMemory()) TR::RegisterDependencyConditions(0, jniLinkageProperties.getNumFloatArgRegs()*2, codeGen->trMemory());
859
for (i = 0; i < jniLinkageProperties.getNumFloatArgRegs()*2; i++)
860
{
861
spillDeps->addPostCondition(codeGen->allocateRegister(TR_FPR), (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fs0 + i));
862
}
863
generateLabelInstruction(codeGen, TR::InstOpCode::label, callNode, spillLabel, spillDeps);
864
865
TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());
866
// mask out the magic bit that indicates JIT frames below
867
generateTrg1ImmInstruction(codeGen, TR::InstOpCode::mov, callNode, gr5Reg, 0, 0);
868
tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetJavaFrameFlagsOffset(), codeGen);
869
generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, callNode, tempMR, gr5Reg);
870
871
// push tag bits (savedA0 slot)
872
// if the current method is simply a wrapper for the JNI call, hide the call-out stack frame
873
uintptr_t tagBits = fej9->constJNICallOutFrameSpecialTag();
874
if (resolvedMethod == comp()->getCurrentMethod())
875
{
876
tagBits |= fej9->constJNICallOutFrameInvisibleTag();
877
}
878
armLoadConstant(callNode, tagBits, gr4Reg, codeGen);
879
tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, -((int)sizeof(uintptr_t)), codeGen);
880
tempMR->setImmediatePreIndexed();
881
generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, callNode, tempMR, gr4Reg);
882
883
// skip unused savedPC slot and push return address (savedCP slot)
884
//
885
TR::LabelSymbol *returnAddrLabel = generateLabelSymbol(codeGen);
886
generateLabelInstruction(codeGen, TR::InstOpCode::add, callNode, returnAddrLabel, NULL, gr4Reg, instrPtr);
887
tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, -2 * ((int)sizeof(uintptr_t)), codeGen);
888
tempMR->setImmediatePreIndexed();
889
generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, callNode, tempMR, gr4Reg);
890
891
// push frame flags
892
intParts flags((int32_t)fej9->constJNICallOutFrameFlags());
893
TR_ASSERT((flags.getValue() & ~0x7FFF0000) == 0, "JNI call-out frame flags have more than 15 bits");
894
generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, callNode, gr4Reg, new (trHeapMemory()) TR_ARMOperand2(flags.getByte3(), 24));
895
generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, callNode, gr4Reg, gr4Reg, new (trHeapMemory()) TR_ARMOperand2(flags.getByte2(), 16));
896
tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, -((int)TR::Compiler->om.sizeofReferenceAddress()), codeGen);
897
tempMR->setImmediatePreIndexed();
898
generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, callNode, tempMR, gr4Reg);
899
900
// push the RAM method for the native
901
intParts ramMethod((int32_t)resolvedMethod->resolvedMethodAddress());
902
generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, callNode, gr4Reg, new (trHeapMemory()) TR_ARMOperand2(ramMethod.getByte3(), 24));
903
generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, callNode, gr4Reg, gr4Reg, new (trHeapMemory()) TR_ARMOperand2(ramMethod.getByte2(), 16));
904
generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, callNode, gr4Reg, gr4Reg, new (trHeapMemory()) TR_ARMOperand2(ramMethod.getByte1(), 8));
905
generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, callNode, gr4Reg, gr4Reg, new (trHeapMemory()) TR_ARMOperand2(ramMethod.getByte0(), 0));
906
tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, -((int)TR::Compiler->om.sizeofReferenceAddress()), codeGen);
907
tempMR->setImmediatePreIndexed();
908
generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, callNode, tempMR, gr4Reg);
909
910
// store the Java SP
911
tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetJavaSPOffset(), codeGen);
912
generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, callNode, tempMR, stackPtr);
913
914
// store the PC and literals values indicating the call-out frame
915
intParts frameType((int32_t)fej9->constJNICallOutFrameType());
916
TR_ASSERT((frameType.getValue() & ~0xFFFF) == 0, "JNI call-out frame type has more than 16 bits");
917
generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, callNode, gr4Reg, new (trHeapMemory()) TR_ARMOperand2(frameType.getByte1(), 8));
918
generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, callNode, gr4Reg, gr4Reg, new (trHeapMemory()) TR_ARMOperand2(frameType.getByte0(), 0));
919
tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetJavaPCOffset(), codeGen);
920
generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, callNode, tempMR, gr4Reg);
921
tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetJavaLiteralsOffset(), codeGen);
922
generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, callNode, tempMR, gr5Reg);
923
924
// the Java arguments for the native method are all in place already; now
925
// pass the vmThread pointer as the hidden first argument to a JNI call
926
generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, callNode, gr0Reg, metaReg);
927
928
// release VM access (go to internalReleaseVMAccess directly)
929
TR::ResolvedMethodSymbol *callerSym = comp()->getJittedMethodSymbol();
930
TR::SymbolReferenceTable *symRefTab = comp()->getSymRefTab();
931
TR::SymbolReference *helperSymRef = symRefTab->findOrCreateReleaseVMAccessSymbolRef(callerSym);
932
933
TR::ARMMultipleMoveInstruction *instr;
934
instr = new (trHeapMemory()) TR::ARMMultipleMoveInstruction(TR::InstOpCode::stmdb, callNode, gr13Reg, 0x0f, codeGen);
935
instr->setWriteBack();
936
937
//AOT relocation is handled in TR::ARMImmSymInstruction::generateBinaryEncoding()
938
TR::Instruction *gcPoint = generateImmSymInstruction(codeGen, TR::InstOpCode::bl, callNode, (uint32_t)helperSymRef->getMethodAddress(), NULL, helperSymRef);
939
gcPoint->ARMNeedsGCMap(~(jniLinkageProperties.getPreservedRegisterMapForGC()));
940
instr = new (trHeapMemory()) TR::ARMMultipleMoveInstruction(TR::InstOpCode::ldmia, callNode, gr13Reg, 0x0f, codeGen);
941
instr->setWriteBack();
942
943
// split dependencies to prevent register assigner from inserting code. Any generated
944
// spills/loads would be incorrect as the stack pointer has not been fixed up yet.
945
TR::RegisterDependencyConditions *postDeps = deps->clone(cg());
946
deps->setNumPostConditions(0, trMemory());
947
postDeps->setNumPreConditions(0, trMemory());
948
// get the target method address and dispatch JNI method directly
949
uintptr_t methodAddress = (uintptr_t)resolvedMethod->startAddressForJNIMethod(comp());
950
//AOT relocation is handled in TR::ARMImmSymInstruction::generateBinaryEncoding()
951
gcPoint = generateImmSymInstruction(codeGen, TR::InstOpCode::bl, callNode, methodAddress, deps, callSymRef);
952
codeGen->getJNICallSites().push_front(new (trHeapMemory()) TR_Pair<TR_ResolvedMethod, TR::Instruction>(calleeSym->getResolvedMethod(), gcPoint));
953
gcPoint->ARMNeedsGCMap(jniLinkageProperties.getPreservedRegisterMapForGC());
954
955
generateLabelInstruction(codeGen, TR::InstOpCode::label, callNode, returnAddrLabel);
956
957
// JNI methods may not return a full register in some cases so we need to
958
// sign- or zero-extend the narrower integer return types properly.
959
switch (resolvedMethod->returnType())
960
{
961
case TR::Int8:
962
if (resolvedMethod->returnTypeIsUnsigned())
963
generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::and_, callNode, returnRegister, returnRegister, 0xFF, 0);
964
else
965
{
966
generateShiftLeftImmediate(codeGen, callNode, returnRegister, returnRegister, 24);
967
generateShiftRightArithmeticImmediate(codeGen, callNode, returnRegister, returnRegister, 24);
968
}
969
break;
970
case TR::Int16:
971
if (resolvedMethod->returnTypeIsUnsigned())
972
{
973
generateTrg1ImmInstruction(codeGen, TR::InstOpCode::mvn, callNode, gr4Reg, 0xFF, 0);
974
generateTrg1Src2Instruction(codeGen, TR::InstOpCode::and_, callNode, returnRegister, returnRegister,
975
new (trHeapMemory()) TR_ARMOperand2(ARMOp2RegLSRImmed, gr4Reg, 16));
976
}
977
else
978
{
979
generateShiftLeftImmediate(codeGen, callNode, returnRegister, returnRegister, 16);
980
generateShiftRightArithmeticImmediate(codeGen, callNode, returnRegister, returnRegister, 16);
981
}
982
break;
983
}
984
985
// if a particular flavour of arm-linux does not support soft-float then any floating point return value will
986
// be in f0 and must be moved to the expected gpr(s).
987
if (codeGen->hasHardFloatReturn())
988
{
989
switch (resolvedMethod->returnType())
990
{
991
case TR::Float:
992
{
993
TR::RealRegister *fpReg = machine->getRealRegister(jniLinkageProperties.getFloatReturnRegister());
994
fpReg->setAssignedRegister(fpReg);
995
tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetFloatTemp1Offset(), codeGen);
996
generateMemSrc1Instruction(codeGen, TR::InstOpCode::fsts, callNode, tempMR, fpReg);
997
generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, returnRegister, tempMR);
998
break;
999
}
1000
case TR::Double:
1001
{
1002
TR::RealRegister *fdReg = machine->getRealRegister(jniLinkageProperties.getDoubleReturnRegister());
1003
fdReg->setAssignedRegister(fdReg);
1004
TR_ASSERT(fej9->thisThreadGetFloatTemp2Offset() - fej9->thisThreadGetFloatTemp1Offset() == 4,"floatTemp1 and floatTemp2 not contiguous");
1005
tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetFloatTemp1Offset(), codeGen);
1006
generateMemSrc1Instruction(codeGen, TR::InstOpCode::fstd, callNode, tempMR, fdReg);
1007
bool bigEndian = codeGen->comp()->target().cpu.isBigEndian();
1008
generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, bigEndian ? returnRegister->getHighOrder() : returnRegister->getLowOrder(), tempMR);
1009
tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetFloatTemp2Offset(), codeGen);
1010
generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, bigEndian ? returnRegister->getLowOrder() : returnRegister->getHighOrder(), tempMR);
1011
break;
1012
}
1013
}
1014
}
1015
1016
// restore the system stack pointer (r13)
1017
if (spSize > 0)
1018
{
1019
TR::RealRegister *sp = machine->getRealRegister(jniLinkageProperties.getStackPointerRegister());
1020
uint32_t base, rotate;
1021
if (constantIsImmed8r(spSize, &base, &rotate))
1022
{
1023
generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, callNode, sp, sp, base, rotate);
1024
}
1025
else
1026
{
1027
TR::Register *tmpReg = codeGen->allocateRegister();
1028
armLoadConstant(callNode, spSize, gr4Reg, codeGen);
1029
generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, callNode, sp, sp, gr4Reg);
1030
}
1031
}
1032
1033
// re-acquire VM access
1034
helperSymRef = symRefTab->findOrCreateAcquireVMAccessSymbolRef(callerSym);
1035
//AOT relocation is handled in TR::ARMImmSymInstruction::generateBinaryEncoding()
1036
gcPoint = generateImmSymInstruction(codeGen, TR::InstOpCode::bl, callNode, (uint32_t)helperSymRef->getMethodAddress(), NULL, helperSymRef);
1037
gcPoint->ARMNeedsGCMap(1 << (jniLinkageProperties.getIntegerReturnRegister() - TR::RealRegister::FirstGPR));
1038
1039
// JNI methods return objects with an extra level of indirection (unless
1040
// the result is NULL) so we need to dereference the return register;
1041
// This dereference must be done after vm access is re-acquired so the underlying
1042
// object is not moved by gc.
1043
if (resolvedMethod->returnType() == TR::Address)
1044
{
1045
tempMR = new (trHeapMemory()) TR::MemoryReference(returnRegister, 0, codeGen);
1046
generateSrc1ImmInstruction(codeGen, TR::InstOpCode::cmp, callNode, returnRegister, 0, 0);
1047
gcPoint = generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, returnRegister, tempMR);
1048
gcPoint->setConditionCode(ARMConditionCodeNE);
1049
}
1050
1051
// restore stack pointer and deal with possibly grown stack
1052
tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetJavaLiteralsOffset(), codeGen);
1053
generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, gr4Reg, tempMR);
1054
tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetJavaSPOffset(), codeGen);
1055
generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, stackPtr, tempMR);
1056
generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, callNode, stackPtr, stackPtr, gr4Reg);
1057
1058
// see if the reference pool was used and, if used, clean it up; otherwise we can
1059
// leave a bunch of pinned garbage behind that screws up the GC quality forever
1060
tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, fej9->constJNICallOutFrameFlagsOffset(), codeGen);
1061
generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, gr4Reg, tempMR);
1062
1063
uint32_t flagValue = fej9->constJNIReferenceFrameAllocatedFlags();
1064
uint32_t base, rotate;
1065
if (constantIsImmed8r(flagValue, &base, &rotate))
1066
{
1067
generateSrc1ImmInstruction(codeGen, TR::InstOpCode::tst, callNode, gr4Reg, base, rotate);
1068
}
1069
else
1070
{
1071
armLoadConstant(callNode, flagValue, gr5Reg, codeGen);
1072
generateSrc2Instruction(codeGen, TR::InstOpCode::tst, callNode, gr4Reg, gr5Reg);
1073
}
1074
1075
helperSymRef = codeGen->symRefTab()->findOrCreateRuntimeHelper(TR_ARMjitCollapseJNIReferenceFrame);
1076
//AOT relocation is handled in TR::ARMImmSymInstruction::generateBinaryEncoding()
1077
generateImmSymInstruction(codeGen, TR::InstOpCode::bl, callNode, (uint32_t)helperSymRef->getMethodAddress(), NULL, helperSymRef, NULL, NULL, ARMConditionCodeEQ);
1078
1079
// restore the JIT frame
1080
generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, callNode, stackPtr, stackPtr, 20, 0);
1081
1082
// check exceptions
1083
tempMR = new (trHeapMemory()) TR::MemoryReference(metaReg, fej9->thisThreadGetCurrentExceptionOffset(), codeGen);
1084
generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, gr4Reg, tempMR);
1085
generateSrc1ImmInstruction(codeGen, TR::InstOpCode::cmp, callNode, gr4Reg, 0, 0);
1086
helperSymRef = symRefTab->findOrCreateThrowCurrentExceptionSymbolRef(callerSym);
1087
//AOT relocation is handled in TR::ARMImmSymInstruction::generateBinaryEncoding()
1088
gcPoint = generateImmSymInstruction(codeGen, TR::InstOpCode::bl, callNode, (uint32_t)helperSymRef->getMethodAddress(), NULL, helperSymRef, NULL, NULL, ARMConditionCodeNE);
1089
gcPoint->ARMNeedsGCMap(1 << (jniLinkageProperties.getIntegerReturnRegister() - TR::RealRegister::FirstGPR));
1090
1091
TR::LabelSymbol *doneLabel = generateLabelSymbol(codeGen);
1092
generateLabelInstruction(codeGen, TR::InstOpCode::label, callNode, doneLabel, postDeps);
1093
1094
return callNode->setRegister(returnRegister);
1095
}
1096
1097