Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/arm/codegen/ARMPrivateLinkage.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/ARMPrivateLinkage.hpp"
24
25
#include "arm/codegen/ARMInstruction.hpp"
26
#include "codegen/CallSnippet.hpp"
27
#include "codegen/GCStackAtlas.hpp"
28
#include "codegen/GCStackMap.hpp"
29
#include "codegen/GenerateInstructions.hpp"
30
#include "codegen/Linkage_inlines.hpp"
31
#include "codegen/Machine.hpp"
32
#include "codegen/Register.hpp"
33
#include "codegen/RegisterPair.hpp"
34
#include "codegen/Snippet.hpp"
35
#include "codegen/StackCheckFailureSnippet.hpp"
36
#include "env/CompilerEnv.hpp"
37
#include "env/J2IThunk.hpp"
38
#include "il/Node.hpp"
39
#include "il/Node_inlines.hpp"
40
#include "il/TreeTop.hpp"
41
#include "il/TreeTop_inlines.hpp"
42
#include "il/LabelSymbol.hpp"
43
#include "il/MethodSymbol.hpp"
44
#include "il/ParameterSymbol.hpp"
45
#include "il/RegisterMappedSymbol.hpp"
46
#include "il/ResolvedMethodSymbol.hpp"
47
#include "il/StaticSymbol.hpp"
48
#include "il/Symbol.hpp"
49
#include "env/VMJ9.h"
50
51
#define LOCK_R14
52
// #define DEBUG_ARM_LINKAGE
53
54
TR::ARMLinkageProperties J9::ARM::PrivateLinkage::properties =
55
{ // TR_Private
56
0, // linkage properties
57
{ // register flags
58
0, // NoReg
59
0, // gr0
60
0, // gr1
61
0, // gr2
62
0, // gr3
63
0, /*Preserved,*/ // gr4
64
0, /*Preserved,*/ // gr5
65
Preserved, // gr6 Java BP
66
Preserved, // gr7 Java SP
67
Preserved, // gr8 Java J9VMThread
68
Preserved, // gr9
69
Preserved, // gr10
70
0, /* Preserved,*/ // gr11 APCS FP (ignore for now - use as temp)
71
Preserved, // gr12 (OS RESERVED)
72
0, /* Preserved,*/ // gr13 APCS SP (OS RESERVED)
73
0, // gr14 LR
74
0, // gr15 IP
75
#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
76
0, // f0
77
0, // f1
78
0, // f2
79
0, // f3
80
0, // f4
81
0, // f5
82
0, // f6
83
0, // f7
84
0, // f8
85
0, // f9
86
0, // f10
87
0, // f11
88
0, // f12
89
0, // f13
90
0, // f14
91
0, // f15
92
#else
93
FloatReturn, // f0
94
0, // f1
95
0, // f2
96
0, // f3
97
Preserved, // f4
98
Preserved, // f5
99
Preserved, // f6
100
Preserved, // f7
101
#endif
102
},
103
{ // preserved registers
104
// TR::RealRegister::gr4,
105
// TR::RealRegister::gr5,
106
TR::RealRegister::gr6,
107
TR::RealRegister::gr7,
108
TR::RealRegister::gr8,
109
TR::RealRegister::gr9,
110
TR::RealRegister::gr10,
111
// TR::RealRegister::gr11,
112
// TR::RealRegister::gr13,
113
// TR::RealRegister::gr14,
114
TR::RealRegister::gr15,
115
#if !defined(__VFP_FP__) || defined(__SOFTFP__)
116
TR::RealRegister::fp4,
117
TR::RealRegister::fp5,
118
TR::RealRegister::fp6,
119
TR::RealRegister::fp7
120
#endif
121
},
122
{ // argument registers
123
TR::RealRegister::gr0,
124
TR::RealRegister::gr1,
125
TR::RealRegister::gr2,
126
TR::RealRegister::gr3,
127
#if !defined(__VFP_FP__) || defined(__SOFTFP__)
128
TR::RealRegister::fp0,
129
TR::RealRegister::fp1,
130
TR::RealRegister::fp2,
131
TR::RealRegister::fp3,
132
#endif
133
},
134
{ // return registers
135
TR::RealRegister::gr0,
136
TR::RealRegister::gr1,
137
#if !defined(__VFP_FP__) || defined(__SOFTFP__)
138
TR::RealRegister::fp0,
139
#endif
140
},
141
MAX_ARM_GLOBAL_GPRS, // numAllocatableIntegerRegisters
142
MAX_ARM_GLOBAL_FPRS, // numAllocatableFloatRegisters
143
0x0000FFC0, // preserved register map
144
TR::RealRegister::gr6, // frame register
145
TR::RealRegister::gr8, // method meta data register
146
TR::RealRegister::gr7, // stack pointer register
147
TR::RealRegister::gr11, // vtable index register
148
TR::RealRegister::gr0, // j9method argument register
149
15, // numberOfDependencyRegisters
150
-4, // offsetToFirstLocal
151
4, // numIntegerArgumentRegisters
152
0, // firstIntegerArgumentRegister
153
#if defined(__VFP_FP__) && !defined(__SOFTFP__)
154
0, // numFloatArgumentRegisters
155
#else
156
4, // numFloatArgumentRegisters
157
#endif
158
0, // firstFloatArgumentRegister
159
0, // firstIntegerReturnRegister
160
0 // firstFloatReturnRegister
161
};
162
163
J9::ARM::PrivateLinkage::PrivateLinkage(TR::CodeGenerator *cg)
164
: J9::PrivateLinkage(cg)
165
{
166
setOffsetToFirstParm(0);
167
}
168
169
TR::ARMLinkageProperties& J9::ARM::PrivateLinkage::getProperties()
170
{
171
return properties;
172
}
173
174
static void lockRegister(TR::RealRegister *regToAssign)
175
{
176
regToAssign->setState(TR::RealRegister::Locked);
177
regToAssign->setAssignedRegister(regToAssign);
178
}
179
180
void J9::ARM::PrivateLinkage::initARMRealRegisterLinkage()
181
{
182
TR::CodeGenerator *codeGen = cg();
183
TR::Machine *machine = codeGen->machine();
184
const TR::ARMLinkageProperties &linkage = getProperties();
185
int icount;
186
187
for (icount = TR::RealRegister::FirstGPR; icount <= TR::RealRegister::gr5; icount++)
188
{
189
machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(icount);
190
}
191
192
// mark all magic registers as locked and having a physical
193
// register associated so the register assigner stays happy
194
lockRegister(codeGen->getMethodMetaDataRegister());
195
lockRegister(codeGen->getFrameRegister());
196
lockRegister(codeGen->machine()->getRealRegister(properties.getStackPointerRegister()));
197
lockRegister(machine->getRealRegister(TR::RealRegister::gr12)); // r12 is OS reserved
198
lockRegister(machine->getRealRegister(TR::RealRegister::gr13)); // r13 is OS SP
199
#ifdef LOCK_R14
200
lockRegister(machine->getRealRegister(TR::RealRegister::gr14)); // r14 is LR
201
#endif
202
lockRegister(machine->getRealRegister(TR::RealRegister::gr15)); // r15 is IP
203
204
for (icount=TR::RealRegister::LastGPR; icount>=TR::RealRegister::gr6; icount--)
205
machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(0xf000-icount);
206
207
#if defined(__VFP_FP__) && !defined(__SOFTFP__)
208
for (icount=TR::RealRegister::FirstFPR; icount<=TR::RealRegister::LastFPR; icount++)
209
machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(icount);
210
#else
211
for (icount=TR::RealRegister::FirstFPR; icount<=TR::RealRegister::fp3; icount++)
212
machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(icount);
213
214
for (icount=TR::RealRegister::LastFPR; icount>=TR::RealRegister::fp4; icount--)
215
machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(0xf000-icount);
216
#endif
217
}
218
219
uint32_t J9::ARM::PrivateLinkage::getRightToLeft()
220
{
221
return getProperties().getRightToLeft();
222
}
223
224
void J9::ARM::PrivateLinkage::mapStack(TR::ResolvedMethodSymbol *method)
225
{
226
ListIterator<TR::AutomaticSymbol> automaticIterator(&method->getAutomaticList());
227
TR::AutomaticSymbol *localCursor = automaticIterator.getFirst();
228
const TR::ARMLinkageProperties& linkage = getProperties();
229
TR::CodeGenerator *codeGen = cg();
230
TR::Machine *machine = codeGen->machine();
231
int32_t firstLocalOffset = linkage.getOffsetToFirstLocal();
232
uint32_t stackIndex = firstLocalOffset;
233
int32_t lowGCOffset;
234
TR::GCStackAtlas *atlas = codeGen->getStackAtlas();
235
236
// map all garbage collected references together so can concisely represent
237
// stack maps. They must be mapped so that the GC map index in each local
238
// symbol is honoured.
239
240
lowGCOffset = stackIndex;
241
int32_t firstLocalGCIndex = atlas->getNumberOfParmSlotsMapped();
242
243
stackIndex -= (atlas->getNumberOfSlotsMapped() - atlas->getNumberOfParmSlotsMapped()) << 2;
244
245
// Map local references again to set the stack position correct according to
246
// the GC map index.
247
//
248
for (localCursor = automaticIterator.getFirst(); localCursor; localCursor = automaticIterator.getNext())
249
if (localCursor->getGCMapIndex() >= 0)
250
{
251
localCursor->setOffset(stackIndex + 4 * (localCursor->getGCMapIndex() - firstLocalGCIndex));
252
if (localCursor->getGCMapIndex() == atlas->getIndexOfFirstInternalPointer())
253
{
254
atlas->setOffsetOfFirstInternalPointer(localCursor->getOffset() - firstLocalOffset);
255
}
256
}
257
258
method->setObjectTempSlots((lowGCOffset-stackIndex) >> 2);
259
lowGCOffset = stackIndex;
260
261
// Now map the rest of the locals
262
//
263
automaticIterator.reset();
264
localCursor = automaticIterator.getFirst();
265
266
while (localCursor != NULL)
267
{
268
if (localCursor->getGCMapIndex() < 0 &&
269
localCursor->getDataType() != TR::Double)
270
{
271
mapSingleAutomatic(localCursor, stackIndex);
272
}
273
localCursor = automaticIterator.getNext();
274
}
275
276
automaticIterator.reset();
277
localCursor = automaticIterator.getFirst();
278
279
while (localCursor != NULL)
280
{
281
if (localCursor->getDataType() == TR::Double)
282
{
283
stackIndex -= (stackIndex & 0x4)?4:0;
284
mapSingleAutomatic(localCursor, stackIndex);
285
}
286
localCursor = automaticIterator.getNext();
287
}
288
method->setLocalMappingCursor(stackIndex);
289
290
ListIterator<TR::ParameterSymbol> parameterIterator(&method->getParameterList());
291
TR::ParameterSymbol *parmCursor = parameterIterator.getFirst();
292
int32_t offsetToFirstParm = getOffsetToFirstParm();
293
if (linkage.getRightToLeft())
294
{
295
while (parmCursor != NULL)
296
{
297
parmCursor->setParameterOffset(parmCursor->getParameterOffset() + offsetToFirstParm);
298
parmCursor = parameterIterator.getNext();
299
}
300
}
301
else
302
{
303
uint32_t sizeOfParameterArea = method->getNumParameterSlots() << 2;
304
while (parmCursor != NULL)
305
{
306
parmCursor->setParameterOffset(sizeOfParameterArea -
307
parmCursor->getParameterOffset() -
308
parmCursor->getSize() +
309
offsetToFirstParm);
310
parmCursor = parameterIterator.getNext();
311
}
312
}
313
314
atlas->setLocalBaseOffset(lowGCOffset - firstLocalOffset);
315
atlas->setParmBaseOffset(atlas->getParmBaseOffset() + offsetToFirstParm - firstLocalOffset);
316
}
317
318
void J9::ARM::PrivateLinkage::mapSingleAutomatic(TR::AutomaticSymbol *p, uint32_t &stackIndex)
319
{
320
int32_t roundedSize = (p->getSize()+3)&(~3);
321
if (roundedSize == 0)
322
roundedSize = 4;
323
324
p->setOffset(stackIndex -= roundedSize);
325
}
326
327
void J9::ARM::PrivateLinkage::setParameterLinkageRegisterIndex(TR::ResolvedMethodSymbol *method)
328
{
329
ListIterator<TR::ParameterSymbol> paramIterator(&(method->getParameterList()));
330
TR::ParameterSymbol *paramCursor = paramIterator.getFirst();
331
int32_t numIntArgs = 0;
332
const TR::ARMLinkageProperties& properties = getProperties();
333
334
while ( (paramCursor!=NULL) &&
335
(numIntArgs < properties.getNumIntArgRegs()) )
336
{
337
int32_t index = -1;
338
339
switch (paramCursor->getDataType())
340
{
341
case TR::Int8:
342
case TR::Int16:
343
case TR::Int32:
344
case TR::Address:
345
case TR::Float://float args are passed in gpr
346
if (numIntArgs<properties.getNumIntArgRegs())
347
{
348
index = numIntArgs;
349
}
350
numIntArgs++;
351
break;
352
case TR::Int64:
353
case TR::Double://float args are passed in 2 gprs
354
if (numIntArgs<properties.getNumIntArgRegs())
355
{
356
index = numIntArgs;
357
}
358
numIntArgs += 2;
359
break;
360
}
361
paramCursor->setLinkageRegisterIndex(index);
362
paramCursor = paramIterator.getNext();
363
}
364
365
}
366
367
// the following three functions are to be modified together
368
// all lists are dealing with the _preserved_ registers on the machine
369
uint16_t getAssignedRegisterList(TR::Machine *machine, const TR::ARMLinkageProperties *linkage)
370
{
371
uint16_t assignedRegisters = 0;
372
373
for(int i = TR::RealRegister::LastGPR; i; i--)
374
{
375
assignedRegisters <<= 1;
376
if(linkage->getPreserved((TR::RealRegister::RegNum)i))
377
{
378
assignedRegisters |= machine->getRealRegister((TR::RealRegister::RegNum)i)->getHasBeenAssignedInMethod();
379
}
380
}
381
382
return assignedRegisters;
383
}
384
385
uint16_t getAssignedRegisterCount(TR::Machine *machine, const TR::ARMLinkageProperties *linkage)
386
{
387
uint16_t assignedRegisters = 0;
388
389
for (int i = TR::RealRegister::LastGPR; i; i--)
390
{
391
if (linkage->getPreserved((TR::RealRegister::RegNum)i))
392
{
393
assignedRegisters += machine->getRealRegister((TR::RealRegister::RegNum)i)->getHasBeenAssignedInMethod() ? 1 : 0;
394
}
395
}
396
397
return assignedRegisters;
398
}
399
400
TR::RealRegister::RegNum getSingleAssignedRegister(TR::Machine *machine, const TR::ARMLinkageProperties *linkage)
401
{
402
for (int i = TR::RealRegister::LastGPR; i; i--)
403
if (linkage->getPreserved((TR::RealRegister::RegNum)i) &&
404
machine->getRealRegister((TR::RealRegister::RegNum)i)->getHasBeenAssignedInMethod())
405
return (TR::RealRegister::RegNum) i;
406
return (TR::RealRegister::RegNum) -1;
407
}
408
409
// OLD FRAME SHAPE NEW FRAME SHAPE
410
//
411
// + + + +
412
// | caller's frame | | caller's frame |
413
// +==========================+ <-+ BP +==========================+
414
// | locals | | | return address* |
415
// | register saves | | +--------------------------+ <-+ BP
416
// | outgoing arguments | size | locals | |
417
// | callee's return address* | | | register saves | size
418
// | (hole)* | | | outgoing arguments | |
419
// +==========================+ <-+ SP +==========================+ <-+ SP
420
// | callee's frame | | caller's frame |
421
//
422
// * Linkage slots are not needed in leaf methods. (TODO)
423
424
void J9::ARM::PrivateLinkage::createPrologue(TR::Instruction *cursor)
425
{
426
TR::CodeGenerator *codeGen = cg();
427
TR::Machine *machine = codeGen->machine();
428
TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol();
429
TR::RealRegister *stackPtr = machine->getRealRegister(properties.getStackPointerRegister());
430
TR::RealRegister *metaBase = codeGen->getMethodMetaDataRegister();
431
TR::Node *firstNode = comp()->getStartTree()->getNode();
432
int i;
433
434
const TR::ARMLinkageProperties& linkage = getProperties();
435
436
int32_t localSize = -((int32_t)bodySymbol->getLocalMappingCursor());
437
int32_t intRegistersSaved = getAssignedRegisterCount(machine, &linkage);
438
int32_t registerSaveDescription = getAssignedRegisterList(machine, &linkage);
439
440
TR::RealRegister::RegNum lastSavedFPR = TR::RealRegister::LastFPR;
441
while (lastSavedFPR >= TR::RealRegister::fp8 &&
442
!machine->getRealRegister(lastSavedFPR)->getHasBeenAssignedInMethod())
443
{
444
lastSavedFPR = (TR::RealRegister::RegNum)((uint32_t)lastSavedFPR - 1);
445
}
446
447
// TODO Fit GPR and FPR save data into (lower) 16 bits of descriptor.
448
int32_t fpRegistersSaved = (int32_t)lastSavedFPR + 1 - (int32_t)TR::RealRegister::fp8;
449
450
int32_t registerSaveSize = intRegistersSaved * 4 + fpRegistersSaved * 8;
451
452
int32_t outgoingArgSize = getOffsetToFirstParm() + codeGen->getLargestOutgoingArgSize();
453
int32_t totalFrameSize = localSize + registerSaveSize + outgoingArgSize;
454
455
// Align frame to 8-byte boundaries.
456
if (debug("alignStackFrame"))
457
totalFrameSize += ((totalFrameSize & 4) ? 4 : 0);
458
459
int32_t resudialSize = totalFrameSize + properties.getOffsetToFirstLocal();
460
461
codeGen->setFrameSizeInBytes(resudialSize);
462
463
// Put offset to saved registers in top 16 bit of descriptor.
464
int32_t offsetToSavedRegisters = localSize + properties.getOffsetToFirstLocal() + registerSaveSize;
465
TR_ASSERT(offsetToSavedRegisters < 65536,
466
"offset to saved registers from base of stack frame must be less than 2^16\n");
467
registerSaveDescription |= (offsetToSavedRegisters << 16);
468
codeGen->setRegisterSaveDescription(registerSaveDescription);
469
470
if (comp()->getOption(TR_EntryBreakPoints))
471
{
472
cursor = new (trHeapMemory()) TR::Instruction(cursor, TR::InstOpCode::bad, firstNode, codeGen);
473
}
474
475
// TODO Only save arguments if full-speed debugging is enabled; otherwise, they
476
// TODO should be moved from the registers in which they reside to the ones in
477
// TODO which the method body expects them. See copyParametersToHomeLocation in
478
// TODO the AMD64 codegen.
479
//
480
cursor = saveArguments(cursor);
481
482
TR::RealRegister *gr4 = machine->getRealRegister(TR::RealRegister::gr4);
483
TR::RealRegister *gr5 = machine->getRealRegister(TR::RealRegister::gr5);
484
TR::RealRegister *gr11 = machine->getRealRegister(TR::RealRegister::gr11);
485
TR::RealRegister *gr14 = machine->getRealRegister(TR::RealRegister::gr14);
486
TR::MemoryReference *tempMR = NULL;
487
uint32_t base, rotate;
488
489
// Save return address, decrement the stack pointer, and check for stack
490
// overflow.
491
//
492
if (!codeGen->getSnippetList().empty() ||
493
bodySymbol->isEHAware() ||
494
machine->getLinkRegisterKilled())
495
{
496
tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, -4, codeGen);
497
cursor = generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, firstNode, tempMR, gr14, cursor);
498
}
499
500
if (constantIsImmed8r(totalFrameSize, &base, &rotate))
501
{
502
cursor = generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::sub, firstNode, stackPtr, stackPtr, base, rotate, cursor);
503
}
504
else
505
{
506
cursor = armLoadConstant(firstNode, totalFrameSize, gr11, codeGen, cursor);
507
cursor = generateTrg1Src2Instruction(codeGen, TR::InstOpCode::sub, firstNode, stackPtr, stackPtr, gr11, cursor);
508
}
509
510
if (!comp()->isDLT())
511
{
512
tempMR = new (trHeapMemory()) TR::MemoryReference(metaBase, codeGen->getStackLimitOffset(), codeGen);
513
cursor = generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, firstNode, gr4, tempMR, cursor);
514
cursor = generateSrc2Instruction(codeGen, TR::InstOpCode::cmp, firstNode, stackPtr, gr4, cursor);
515
516
TR::LabelSymbol *snippetLabel = generateLabelSymbol(codeGen);
517
TR::LabelSymbol *restartLabel = generateLabelSymbol(codeGen);
518
519
cursor = generateConditionalBranchInstruction(codeGen, firstNode, ARMConditionCodeLS, snippetLabel, cursor);
520
521
TR::Snippet *snippet = new (trHeapMemory()) TR::ARMStackCheckFailureSnippet(codeGen, cursor->getNode(), restartLabel, snippetLabel);
522
snippet->resetNeedsExceptionTableEntry();
523
codeGen->addSnippet(snippet);
524
525
cursor = generateLabelInstruction(codeGen, TR::InstOpCode::label, firstNode, restartLabel, cursor);
526
}
527
528
// Save preserved registers.
529
// outgoingArgSize <= 1020 because the JVM spec limits the max number of method param to 255, so constantIsImmed8r can handle outgoingArgSize.
530
if (intRegistersSaved)
531
{
532
if (1 == intRegistersSaved)
533
{
534
TR::Register *reg = machine->getRealRegister(getSingleAssignedRegister(machine, &linkage));
535
tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, outgoingArgSize, codeGen);
536
cursor = generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, firstNode, tempMR, reg, cursor);
537
}
538
else
539
{
540
constantIsImmed8r(outgoingArgSize, &base, &rotate);
541
cursor = generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, firstNode, gr4, stackPtr, base, rotate, cursor);
542
// FIXME Need generateMultiMoveInstruction().
543
cursor = new (trHeapMemory()) TR::ARMMultipleMoveInstruction(cursor, TR::InstOpCode::stm, firstNode, gr4, getAssignedRegisterList(machine, &linkage), codeGen);
544
}
545
}
546
547
// for saving preserved VFP registers, the offset can be larger than 1024, so constantIsImmed10 and constantIsImmed8r might not be able to handle the offset.
548
outgoingArgSize += intRegistersSaved * 4;
549
if (fpRegistersSaved > 0)
550
{
551
if (1 == fpRegistersSaved)
552
{
553
TR::Register *reg = machine->getRealRegister(lastSavedFPR);
554
if (constantIsImmed10(outgoingArgSize))
555
{
556
tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, outgoingArgSize, codeGen);
557
}
558
else
559
{
560
cursor = armLoadConstant(firstNode, outgoingArgSize, gr4, codeGen, cursor);
561
cursor = generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, firstNode, gr4, stackPtr, gr4, cursor);
562
tempMR = new (trHeapMemory()) TR::MemoryReference(gr4, 0, codeGen);
563
}
564
cursor = generateMemSrc1Instruction(codeGen, TR::InstOpCode::fstd, firstNode, tempMR, reg, cursor);
565
}
566
else
567
{
568
if (constantIsImmed8r(outgoingArgSize, &base, &rotate))
569
{
570
cursor = generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, firstNode, gr4, stackPtr, base, rotate, cursor);
571
}
572
else
573
{
574
cursor = armLoadConstant(firstNode, outgoingArgSize, gr4, codeGen, cursor);
575
cursor = generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, firstNode, gr4, stackPtr, gr4, cursor);
576
}
577
// FIXME Need generateMultiMoveInstruction().
578
uint16_t offset = ((TR::RealRegister::fp8 - TR::RealRegister::FirstFPR) << 12) | (fpRegistersSaved << 1);
579
cursor = new (trHeapMemory()) TR::ARMMultipleMoveInstruction(cursor, TR::InstOpCode::fstmd, firstNode, gr4, offset, codeGen);
580
((TR::ARMMultipleMoveInstruction *)cursor)->setIncrement();
581
}
582
}
583
584
// Initialize reference-type locals to NULL.
585
TR::GCStackAtlas *atlas = codeGen->getStackAtlas();
586
if (atlas)
587
{
588
uint32_t numLocalsToBeInitialized = atlas->getNumberOfSlotsToBeInitialized();
589
590
// TODO Support internal pointers.
591
if (numLocalsToBeInitialized > 0)
592
{
593
uint32_t offset = resudialSize + atlas->getLocalBaseOffset();
594
cursor = armLoadConstant(firstNode, NULLVALUE, gr11, codeGen, cursor);
595
596
if (numLocalsToBeInitialized > 0)
597
{
598
#if 0
599
traceMsg("%d locals to be initialized in %s\n",
600
numLocalsToBeInitialized,
601
signature(TR::comp()->getCurrentMethod()));
602
#endif
603
// Inline zero initialization if the number of stores is small;
604
// otherwise, set up a loop to perform the initialization.
605
if (numLocalsToBeInitialized > 8)
606
{
607
TR::LabelSymbol *loopLabel = generateLabelSymbol(codeGen);
608
cursor = armLoadConstant(firstNode, offset, gr4, codeGen, cursor);
609
cursor = generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, firstNode, gr4, gr4, stackPtr, cursor);
610
cursor = armLoadConstant(firstNode, (numLocalsToBeInitialized - 1) << 2, gr5, codeGen, cursor);
611
cursor = generateLabelInstruction(codeGen, TR::InstOpCode::label, firstNode, loopLabel, cursor);
612
tempMR = new (trHeapMemory()) TR::MemoryReference(gr4, gr5, codeGen);
613
cursor = generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, firstNode, tempMR, gr11, cursor);
614
cursor = generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::sub_r, firstNode, gr5, gr5, 4, 0, cursor);
615
cursor = generateConditionalBranchInstruction(codeGen, firstNode, ARMConditionCodeGE, loopLabel, cursor);
616
}
617
else
618
{
619
for (uint32_t i = 0; i < numLocalsToBeInitialized; i++, offset += 4)
620
{
621
tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, offset, codeGen);
622
cursor = generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, firstNode, tempMR, gr11, cursor);
623
}
624
}
625
}
626
}
627
628
if (atlas->getInternalPointerMap())
629
{
630
int32_t offset = resudialSize + atlas->getOffsetOfFirstInternalPointer();
631
632
// First collect all pinning arrays that are the base for at least
633
// one derived internal pointer stack slot
634
//
635
int32_t numDistinctPinningArrays = 0;
636
List<TR_InternalPointerPair> seenInternalPtrPairs(trMemory());
637
List<TR::AutomaticSymbol> seenPinningArrays(trMemory());
638
ListIterator<TR_InternalPointerPair> internalPtrIt(&atlas->getInternalPointerMap()->getInternalPointerPairs());
639
for (TR_InternalPointerPair *internalPtrPair = internalPtrIt.getFirst(); internalPtrPair; internalPtrPair = internalPtrIt.getNext())
640
{
641
bool seenPinningArrayBefore = false;
642
ListIterator<TR_InternalPointerPair> seenInternalPtrIt(&seenInternalPtrPairs);
643
for (TR_InternalPointerPair *seenInternalPtrPair = seenInternalPtrIt.getFirst(); seenInternalPtrPair && (seenInternalPtrPair != internalPtrPair); seenInternalPtrPair = seenInternalPtrIt.getNext())
644
{
645
if (internalPtrPair->getPinningArrayPointer() == seenInternalPtrPair->getPinningArrayPointer())
646
{
647
seenPinningArrayBefore = true;
648
break;
649
}
650
}
651
652
if (!seenPinningArrayBefore)
653
{
654
seenPinningArrays.add(internalPtrPair->getPinningArrayPointer());
655
seenInternalPtrPairs.add(internalPtrPair);
656
numDistinctPinningArrays++;
657
}
658
}
659
660
// Now collect all pinning arrays that are the base for only
661
// internal pointers in registers
662
//
663
ListIterator<TR::AutomaticSymbol> autoIt(&atlas->getPinningArrayPtrsForInternalPtrRegs());
664
TR::AutomaticSymbol *autoSymbol;
665
for (autoSymbol = autoIt.getFirst(); autoSymbol != NULL; autoSymbol = autoIt.getNext())
666
{
667
if (!seenPinningArrays.find(autoSymbol))
668
{
669
seenPinningArrays.add(autoSymbol);
670
numDistinctPinningArrays++;
671
}
672
}
673
674
// Total number of slots to be initialized is number of pinning arrays +
675
// number of derived internal pointer stack slots
676
//
677
int32_t numSlotsToBeInitialized = numDistinctPinningArrays + atlas->getInternalPointerMap()->getNumInternalPointers();
678
679
if ((numSlotsToBeInitialized > 0) && !(numLocalsToBeInitialized > 0))
680
{
681
cursor = armLoadConstant(firstNode, NULLVALUE, gr11, codeGen, cursor);
682
}
683
684
for (i = 0; i < numSlotsToBeInitialized; i++, offset += TR::Compiler->om.sizeofReferenceAddress())
685
{
686
tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, offset, codeGen);
687
cursor = generateMemSrc1Instruction(codeGen, TR::InstOpCode::str, firstNode, tempMR, gr11, cursor);
688
}
689
}
690
691
// FIXME Remove calls to debug("hasFramePointer"). The VM no longer
692
// FIXME supports the use of a frame pointer. The TR_ASSERT() message
693
// FIXME below seems to have been inherited from the PPC codegen, and
694
// FIXME may be completely irrelevant.
695
//
696
if (!debug("hasFramePointer"))
697
{
698
// TR_ASSERT(totalFrameSize <= 1028, "Setting up a frame pointer anyway.");
699
ListIterator<TR::AutomaticSymbol> automaticIterator(&bodySymbol->getAutomaticList());
700
TR::AutomaticSymbol *localCursor = automaticIterator.getFirst();
701
while (localCursor)
702
{
703
localCursor->setOffset(localCursor->getOffset() + totalFrameSize);
704
localCursor = automaticIterator.getNext();
705
}
706
707
ListIterator<TR::ParameterSymbol> parameterIterator(&bodySymbol->getParameterList());
708
TR::ParameterSymbol *parmCursor = parameterIterator.getFirst();
709
while (parmCursor)
710
{
711
parmCursor->setParameterOffset(parmCursor->getParameterOffset() + totalFrameSize);
712
parmCursor = parameterIterator.getNext();
713
}
714
}
715
716
TR_GCStackMap *map = atlas->getLocalMap();
717
map->setLowestOffsetInstruction(cursor);
718
if (!comp()->useRegisterMaps())
719
atlas->addStackMap(map);
720
}
721
}
722
723
void J9::ARM::PrivateLinkage::createEpilogue(TR::Instruction *cursor)
724
{
725
TR::CodeGenerator *codeGen = cg();
726
TR::Machine *machine = codeGen->machine();
727
TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol();
728
TR::RealRegister *stackPtr = machine->getRealRegister(properties.getStackPointerRegister());
729
TR::Node *lastNode = cursor->getNode();
730
731
const TR::ARMLinkageProperties &linkage = getProperties();
732
733
int32_t localSize = -((int32_t)bodySymbol->getLocalMappingCursor());
734
int32_t intRegistersSaved = getAssignedRegisterCount(machine, &linkage);
735
736
TR::RealRegister::RegNum lastSavedFPR = TR::RealRegister::LastFPR;
737
while (lastSavedFPR >= TR::RealRegister::fp8 &&
738
!machine->getRealRegister(lastSavedFPR)->getHasBeenAssignedInMethod())
739
{
740
lastSavedFPR = (TR::RealRegister::RegNum)((uint32_t)lastSavedFPR - 1);
741
}
742
743
// TODO Fit GPR and FPR save data into (lower) 16 bits of descriptor.
744
int32_t fpRegistersSaved = (int32_t)lastSavedFPR + 1 - (int32_t)TR::RealRegister::fp8;
745
746
int32_t registerSaveSize = intRegistersSaved * 4 + fpRegistersSaved * 8;
747
748
int32_t outgoingArgSize = getOffsetToFirstParm() + codeGen->getLargestOutgoingArgSize();
749
int32_t totalFrameSize = localSize + registerSaveSize + outgoingArgSize;
750
751
if (debug("alignStackFrame"))
752
totalFrameSize += ((totalFrameSize & 4) ? 4 : 0);
753
754
// Reload preserved registers.
755
TR::MemoryReference *tempMR;
756
uint32_t base, rotate;
757
758
if (intRegistersSaved)
759
{
760
if (1 == intRegistersSaved)
761
{
762
TR::RealRegister *reg = machine->getRealRegister(getSingleAssignedRegister(machine, &linkage));
763
tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, outgoingArgSize, codeGen);
764
cursor = generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, lastNode, reg, tempMR, cursor);
765
}
766
else
767
{
768
TR::RealRegister *gr4 = machine->getRealRegister(TR::RealRegister::gr4);
769
constantIsImmed8r(outgoingArgSize, &base, &rotate);
770
cursor = generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, lastNode, gr4, stackPtr, base, rotate, cursor);
771
cursor = new (trHeapMemory()) TR::ARMMultipleMoveInstruction(cursor, TR::InstOpCode::ldm, lastNode, gr4, getAssignedRegisterList(machine, &linkage), codeGen);
772
}
773
}
774
775
outgoingArgSize += intRegistersSaved * 4;
776
if (fpRegistersSaved > 0)
777
{
778
TR::RealRegister *gr4 = machine->getRealRegister(TR::RealRegister::gr4);
779
if (1 == fpRegistersSaved)
780
{
781
TR::Register *reg = machine->getRealRegister(lastSavedFPR);
782
if (constantIsImmed10(outgoingArgSize))
783
{
784
tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, outgoingArgSize, codeGen);
785
}
786
else
787
{
788
cursor = armLoadConstant(lastNode, outgoingArgSize, gr4, codeGen, cursor);
789
cursor = generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, lastNode, gr4, stackPtr, gr4, cursor);
790
tempMR = new (trHeapMemory()) TR::MemoryReference(gr4, 0, codeGen);
791
}
792
cursor = generateMemSrc1Instruction(codeGen, TR::InstOpCode::fldd, lastNode, tempMR, reg, cursor);
793
}
794
else
795
{
796
if (constantIsImmed8r(outgoingArgSize, &base, &rotate))
797
{
798
cursor = generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, lastNode, gr4, stackPtr, base, rotate, cursor);
799
}
800
else
801
{
802
cursor = armLoadConstant(lastNode, outgoingArgSize, gr4, codeGen, cursor);
803
cursor = generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, lastNode, gr4, stackPtr, gr4, cursor);
804
}
805
// FIXME Need generateMultiMoveInstruction().
806
uint16_t offset = ((TR::RealRegister::fp8 - TR::RealRegister::FirstFPR) << 12) | (fpRegistersSaved << 1);
807
cursor = new (trHeapMemory()) TR::ARMMultipleMoveInstruction(cursor, TR::InstOpCode::fldmd, lastNode, gr4, offset, codeGen);
808
((TR::ARMMultipleMoveInstruction *)cursor)->setIncrement();
809
}
810
}
811
812
// Reload return address.
813
TR::RealRegister *gr14 = machine->getRealRegister(TR::RealRegister::gr14);
814
TR::RealRegister *gr15 = machine->getRealRegister(TR::RealRegister::gr15);
815
816
if (codeGen->getSnippetList().size() > 1 ||
817
(comp()->isDLT() && !codeGen->getSnippetList().empty()) ||
818
bodySymbol->isEHAware() ||
819
machine->getLinkRegisterKilled())
820
{
821
tempMR = new (trHeapMemory()) TR::MemoryReference(stackPtr, totalFrameSize + properties.getOffsetToFirstLocal(), codeGen);
822
cursor = generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, lastNode, gr14, tempMR, cursor);
823
}
824
825
// Collapse stack frame and return.
826
if (constantIsImmed8r(totalFrameSize, &base, &rotate))
827
{
828
cursor = generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, lastNode, stackPtr, stackPtr, base, rotate, cursor);
829
}
830
else
831
{
832
TR::RealRegister *gr4 = machine->getRealRegister(TR::RealRegister::gr4);
833
cursor = armLoadConstant(lastNode, totalFrameSize, gr4, codeGen, cursor);
834
cursor = generateTrg1Src2Instruction(codeGen, TR::InstOpCode::add, lastNode, stackPtr, stackPtr, gr4, cursor);
835
}
836
837
cursor = generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, lastNode, gr15, gr14, cursor);
838
}
839
840
TR::MemoryReference *J9::ARM::PrivateLinkage::getOutgoingArgumentMemRef(int32_t totalSize,
841
int32_t offset,
842
TR::Register *argReg,
843
TR::InstOpCode::Mnemonic opCode,
844
TR::ARMMemoryArgument &memArg)
845
{
846
#ifdef DEBUG_ARM_LINKAGE
847
printf("private: totalSize %d offset %d\n", totalSize, offset); fflush(stdout);
848
#endif
849
850
int32_t spOffset = totalSize - offset - TR::Compiler->om.sizeofReferenceAddress();
851
TR::RealRegister *sp = cg()->machine()->getRealRegister(properties.getStackPointerRegister());
852
TR::MemoryReference *result = new (trHeapMemory()) TR::MemoryReference(sp, spOffset, cg());
853
memArg.argRegister = argReg;
854
memArg.argMemory = result;
855
memArg.opCode = opCode;
856
return result;
857
}
858
859
int32_t J9::ARM::PrivateLinkage::buildArgs(TR::Node *callNode,
860
TR::RegisterDependencyConditions *dependencies,
861
TR::Register* &vftReg,
862
bool isVirtual)
863
{
864
return buildARMLinkageArgs(callNode, dependencies, vftReg, TR_Private, isVirtual);
865
}
866
867
void J9::ARM::PrivateLinkage::buildVirtualDispatch(TR::Node *callNode,
868
TR::RegisterDependencyConditions *dependencies,
869
TR::RegisterDependencyConditions *postDeps,
870
TR::Register *vftReg,
871
uint32_t sizeOfArguments)
872
{
873
TR::CodeGenerator *codeGen = cg();
874
TR::Machine *machine = codeGen->machine();
875
876
#ifdef LOCK_R14
877
/* Dependency #0 is for vftReg. */
878
TR::Register *gr11 = dependencies->searchPreConditionRegister(TR::RealRegister::gr11);
879
TR::Register *gr0 = dependencies->searchPreConditionRegister(TR::RealRegister::gr0);
880
TR::Register *gr4 = dependencies->searchPreConditionRegister(TR::RealRegister::gr4);
881
TR::RealRegister *gr14 = machine->getRealRegister(TR::RealRegister::gr14);
882
TR::RealRegister *gr15 = machine->getRealRegister(TR::RealRegister::gr15);
883
#else
884
TR::Register *gr11 = dependencies->searchPreConditionRegister(TR::RealRegister::gr11);
885
TR::Register *gr14 = dependencies->searchPreConditionRegister(TR::RealRegister::gr14);
886
TR::Register *gr0 = dependencies->searchPreConditionRegister(TR::RealRegister::gr0);
887
TR::Register *gr4 = dependencies->searchPreConditionRegister(TR::RealRegister::gr4);
888
TR::RealRegister *gr15 = machine->getRealRegister(TR::RealRegister::gr15);
889
#endif
890
891
TR::SymbolReference *methodSymRef = callNode->getSymbolReference();
892
TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();
893
TR::LabelSymbol *doneLabel = NULL;
894
TR::Instruction *gcPoint;
895
896
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp()->fe());
897
898
// Computed calls
899
//
900
if (methodSymbol->isComputed())
901
{
902
void *thunk;
903
904
switch (methodSymbol->getMandatoryRecognizedMethod())
905
{
906
case TR::java_lang_invoke_ComputedCalls_dispatchVirtual:
907
{
908
// Need a j2i thunk for the method that will ultimately be dispatched by this handle call
909
char *j2iSignature = fej9->getJ2IThunkSignatureForDispatchVirtual(methodSymbol->getMethod()->signatureChars(), methodSymbol->getMethod()->signatureLength(), comp());
910
int32_t signatureLen = strlen(j2iSignature);
911
thunk = fej9->getJ2IThunk(j2iSignature, signatureLen, comp());
912
if (!thunk)
913
{
914
thunk = fej9->setJ2IThunk(j2iSignature, signatureLen,
915
TR::ARMCallSnippet::generateVIThunk(fej9->getEquivalentVirtualCallNodeForDispatchVirtual(callNode, comp()), sizeOfArguments, codeGen), comp());
916
}
917
}
918
default:
919
if (fej9->needsInvokeExactJ2IThunk(callNode, comp()))
920
{
921
comp()->getPersistentInfo()->getInvokeExactJ2IThunkTable()->addThunk(
922
TR::ARMCallSnippet::generateInvokeExactJ2IThunk(callNode, sizeOfArguments, codeGen, methodSymbol->getMethod()->signatureChars()), fej9);
923
}
924
break;
925
}
926
927
TR::Node *child = callNode->getFirstChild();
928
TR::Register *targetAddress = codeGen->evaluate(child);
929
if (targetAddress->getRegisterPair())
930
{
931
// On 32-bit, we can just ignore the top 32 bits of the 64-bit target address
932
targetAddress = targetAddress->getLowOrder();
933
}
934
doneLabel = generateLabelSymbol(codeGen);
935
generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, callNode, gr4, targetAddress);
936
937
TR::Instruction *instr = generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, callNode, gr14, gr15);
938
instr->setDependencyConditions(dependencies);
939
dependencies->incRegisterTotalUseCounts(codeGen);
940
941
gcPoint = generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, callNode, gr15, gr4);
942
943
gcPoint->ARMNeedsGCMap(getProperties().getPreservedRegisterMapForGC());
944
945
generateLabelInstruction(codeGen, TR::InstOpCode::label, callNode, doneLabel, postDeps);
946
947
return;
948
}
949
950
uint8_t *thunk = (uint8_t*)fej9->getJ2IThunk(methodSymbol->getMethod()->signatureChars(), methodSymbol->getMethod()->signatureLength(), comp());
951
if (!thunk)
952
thunk = (uint8_t*)fej9->setJ2IThunk(methodSymbol->getMethod()->signatureChars(), methodSymbol->getMethod()->signatureLength(), TR::ARMCallSnippet::generateVIThunk(callNode, sizeOfArguments, codeGen), comp());
953
954
if (methodSymbol->isVirtual())
955
{
956
TR::Register * classReg;
957
if (methodSymRef == comp()->getSymRefTab()->findObjectNewInstanceImplSymbol())
958
{//In this case, methodSymRef is resolved and VTable index is small enough to fit in 12bit, so we can safely use gr11 for classReg.
959
classReg = gr11;
960
generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, gr11, new (trHeapMemory()) TR::MemoryReference(gr0, fej9->getOffsetOfClassFromJavaLangClassField(), codeGen));
961
}
962
else
963
{
964
classReg = vftReg;
965
}
966
TR::MemoryReference *tempMR;
967
if (methodSymRef->isUnresolved() || comp()->compileRelocatableCode())
968
{
969
doneLabel = generateLabelSymbol(codeGen);
970
971
TR::LabelSymbol *snippetLabel = generateLabelSymbol(codeGen);
972
codeGen->addSnippet(new (trHeapMemory()) TR::ARMVirtualUnresolvedSnippet(codeGen,
973
callNode,
974
snippetLabel,
975
sizeOfArguments,
976
doneLabel,
977
thunk));
978
979
// These 5 instructions will be ultimately modified to load the
980
// method pointer and move return address to link register.
981
// The 4 instruction before branch should be a no-op if the offset turns
982
// out to be within range (for most cases).
983
generateTrg1ImmInstruction(codeGen, TR::InstOpCode::mov, callNode, gr11, 0, 0);
984
generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, callNode, gr11, gr11, 0, 8);
985
generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, callNode, gr11, gr11, 0, 16);
986
generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::add, callNode, gr11, gr11, 0, 24);
987
988
generateLabelInstruction(codeGen, TR::InstOpCode::b, callNode, snippetLabel, dependencies);
989
990
tempMR = new (trHeapMemory()) TR::MemoryReference(classReg, 0, codeGen);
991
gcPoint = generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, gr15, tempMR);
992
}
993
else
994
{
995
int32_t offset = methodSymRef->getOffset();
996
if (constantIsImmed12(offset))
997
{
998
TR::Instruction *instr = generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, callNode, gr14, gr15);
999
instr->setDependencyConditions(dependencies);
1000
dependencies->incRegisterTotalUseCounts(codeGen);
1001
1002
tempMR = new (trHeapMemory()) TR::MemoryReference(classReg, offset, codeGen);
1003
gcPoint = generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, gr15, tempMR);
1004
gcPoint->setDependencyConditions(postDeps);
1005
postDeps->incRegisterTotalUseCounts(codeGen);
1006
}
1007
else
1008
{
1009
TR::Instruction *instr = armLoadConstant(callNode, offset, gr11, codeGen);
1010
instr = generateTrg1Src1Instruction(codeGen, TR::InstOpCode::mov, callNode, gr14, gr15);
1011
instr->setDependencyConditions(dependencies);
1012
dependencies->incRegisterTotalUseCounts(codeGen);
1013
1014
tempMR = new (trHeapMemory()) TR::MemoryReference(classReg, gr11, 0, codeGen);
1015
gcPoint = generateTrg1MemInstruction(codeGen, TR::InstOpCode::ldr, callNode, gr15, tempMR);
1016
gcPoint->setDependencyConditions(postDeps);
1017
postDeps->incRegisterTotalUseCounts(codeGen);
1018
}
1019
}
1020
}
1021
else
1022
{
1023
// TODO inline interface dispatch and IPIC
1024
doneLabel = generateLabelSymbol(codeGen);
1025
1026
TR::LabelSymbol *snippetLabel = generateLabelSymbol(codeGen);
1027
codeGen->addSnippet(new (trHeapMemory()) TR::ARMInterfaceCallSnippet(codeGen,
1028
callNode,
1029
snippetLabel,
1030
sizeOfArguments,
1031
doneLabel,
1032
thunk));
1033
1034
gcPoint = generateLabelInstruction(codeGen, TR::InstOpCode::b, callNode, snippetLabel, dependencies);
1035
}
1036
1037
gcPoint->ARMNeedsGCMap(getProperties().getPreservedRegisterMapForGC());
1038
1039
// Insert a return label if a snippet is used. The register dependency
1040
// pre-conditions must be anchored on the branch out, and the post-
1041
// conditions must be anchored on the return label.
1042
if (doneLabel)
1043
generateLabelInstruction(codeGen, TR::InstOpCode::label, callNode, doneLabel, postDeps);
1044
1045
return;
1046
}
1047
1048
TR::Register *J9::ARM::PrivateLinkage::buildDirectDispatch(TR::Node *callNode)
1049
{
1050
TR::MethodSymbol *callSym = callNode->getSymbol()->castToMethodSymbol();
1051
if (callSym->isJNI() &&
1052
callNode->isPreparedForDirectJNI())
1053
{
1054
callSym->setLinkage(TR_J9JNILinkage);
1055
TR::Linkage *linkage = cg()->getLinkage(callSym->getLinkageConvention());
1056
1057
return linkage->buildDirectDispatch(callNode);
1058
}
1059
else
1060
{
1061
return buildARMLinkageDirectDispatch(callNode);
1062
}
1063
}
1064
1065
TR::Register *J9::ARM::PrivateLinkage::buildIndirectDispatch(TR::Node *callNode)
1066
{
1067
TR::CodeGenerator *codeGen = cg();
1068
TR::Machine *machine = codeGen->machine();
1069
1070
const TR::ARMLinkageProperties &pp = getProperties();
1071
TR::RegisterDependencyConditions *deps =
1072
new (trHeapMemory()) TR::RegisterDependencyConditions(pp.getNumberOfDependencyGPRegisters() + 8 /*pp.getNumFloatArgRegs()*/,
1073
pp.getNumberOfDependencyGPRegisters() + 8 /* pp.getNumFloatArgRegs()*/, trMemory());
1074
1075
TR::Register *vftReg = NULL;
1076
int32_t argSize = buildArgs(callNode, deps, vftReg, true);
1077
deps->stopAddingConditions();
1078
1079
TR::RegisterDependencyConditions *postDeps = deps->clone(cg());
1080
1081
deps->setNumPostConditions(0, trMemory());
1082
postDeps->setNumPreConditions(0, trMemory());
1083
1084
#ifdef LOCK_R14
1085
/* Dependency #0 is for vftReg. */
1086
TR::Register *gr11 = deps->searchPreConditionRegister(TR::RealRegister::gr11);
1087
TR::Register *gr0 = deps->searchPreConditionRegister(TR::RealRegister::gr0);
1088
TR::RealRegister *gr14 = machine->getRealRegister(TR::RealRegister::gr14);
1089
TR::RealRegister *gr15 = machine->getRealRegister(TR::RealRegister::gr15);
1090
#else
1091
TR::Register *gr11 = deps->searchPreConditionRegister(TR::RealRegister::gr11);
1092
TR::Register *gr14 = deps->searchPreConditionRegister(TR::RealRegister::gr14);
1093
TR::Register *gr0 = deps->searchPreConditionRegister(TR::RealRegister::gr0);
1094
TR::RealRegister *gr15 = machine->getRealRegister(TR::RealRegister::gr15);
1095
#endif
1096
1097
TR::Register *returnRegister;
1098
TR::DataType resType = callNode->getType();
1099
1100
buildVirtualDispatch(callNode, deps, postDeps, vftReg, argSize);
1101
1102
codeGen->machine()->setLinkRegisterKilled(true);
1103
codeGen->setHasCall();
1104
1105
switch(callNode->getOpCodeValue())
1106
{
1107
case TR::icalli:
1108
case TR::acalli:
1109
#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
1110
case TR::fcalli:
1111
#endif
1112
returnRegister = postDeps->searchPostConditionRegister(pp.getIntegerReturnRegister());
1113
if (resType.isFloatingPoint())
1114
{
1115
TR::Register *tempReg = codeGen->allocateSinglePrecisionRegister();
1116
TR::Instruction *cursor = generateTrg1Src1Instruction(codeGen, TR::InstOpCode::fmsr, callNode, tempReg, returnRegister);
1117
returnRegister = tempReg;
1118
}
1119
break;
1120
case TR::lcalli:
1121
#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
1122
case TR::dcalli:
1123
#endif
1124
{
1125
TR::Register *lowReg = postDeps->searchPostConditionRegister(pp.getLongLowReturnRegister());
1126
TR::Register *highReg = postDeps->searchPostConditionRegister(pp.getLongHighReturnRegister());
1127
returnRegister = codeGen->allocateRegisterPair(lowReg, highReg);
1128
if (resType.isDouble())
1129
{
1130
TR::Register *tempReg = codeGen->allocateRegister(TR_FPR);
1131
TR::Instruction *cursor = generateTrg1Src2Instruction(codeGen, TR::InstOpCode::fmdrr, callNode, tempReg, lowReg, highReg);
1132
returnRegister = tempReg;
1133
}
1134
1135
}
1136
break;
1137
#if !defined(__VFP_FP__) || defined(__SOFTFP__)
1138
case TR::fcalli:
1139
case TR::dcalli:
1140
returnRegister = postDeps->searchPostConditionRegister(pp.getFloatReturnRegister());
1141
break;
1142
#endif
1143
case TR::calli:
1144
returnRegister = NULL;
1145
break;
1146
default:
1147
returnRegister = NULL;
1148
TR_ASSERT(0, "Unknown indirect call Opcode.");
1149
}
1150
1151
callNode->setRegister(returnRegister);
1152
return returnRegister;
1153
}
1154
1155
int32_t J9::ARM::HelperLinkage::buildArgs(TR::Node *callNode,
1156
TR::RegisterDependencyConditions *dependencies,
1157
TR::Register* &vftReg,
1158
bool isVirtual)
1159
{
1160
TR_ASSERT(!isVirtual, "virtual helper calls not supported");
1161
return buildARMLinkageArgs(callNode, dependencies, vftReg, TR_Helper, isVirtual);
1162
}
1163
1164