Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/p/codegen/PPCPrivateLinkage.cpp
6004 views
1
/*******************************************************************************
2
* Copyright (c) 2000, 2022 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/PPCPrivateLinkage.hpp"
24
25
#include "codegen/CodeGenerator.hpp"
26
#include "codegen/CodeGeneratorUtils.hpp"
27
#include "codegen/Linkage_inlines.hpp"
28
#include "codegen/LiveRegister.hpp"
29
#include "codegen/Machine.hpp"
30
#include "codegen/RealRegister.hpp"
31
#include "codegen/Register.hpp"
32
#include "codegen/RegisterDependency.hpp"
33
#include "codegen/Snippet.hpp"
34
#include "codegen/TreeEvaluator.hpp"
35
#include "compile/ResolvedMethod.hpp"
36
#include "compile/VirtualGuard.hpp"
37
#include "env/CHTable.hpp"
38
#include "env/CompilerEnv.hpp"
39
#include "env/J2IThunk.hpp"
40
#include "env/PersistentCHTable.hpp"
41
#include "env/VMJ9.h"
42
#include "env/jittypes.h"
43
#include "il/LabelSymbol.hpp"
44
#include "il/Node.hpp"
45
#include "il/Node_inlines.hpp"
46
#include "il/ParameterSymbol.hpp"
47
#include "il/TreeTop.hpp"
48
#include "il/TreeTop_inlines.hpp"
49
#include "p/codegen/CallSnippet.hpp"
50
#include "p/codegen/GenerateInstructions.hpp"
51
#include "p/codegen/PPCEvaluator.hpp"
52
#include "p/codegen/PPCHelperCallSnippet.hpp"
53
#include "p/codegen/PPCInstruction.hpp"
54
#include "p/codegen/PPCTableOfConstants.hpp"
55
#include "p/codegen/StackCheckFailureSnippet.hpp"
56
#include "runtime/J9Profiler.hpp"
57
#include "runtime/J9ValueProfiler.hpp"
58
59
#define MIN_PROFILED_CALL_FREQUENCY (.075f)
60
#define MAX_PROFILED_CALL_FREQUENCY (.90f)
61
62
J9::Power::PrivateLinkage::PrivateLinkage(TR::CodeGenerator *cg)
63
: J9::PrivateLinkage(cg)
64
{
65
TR::Compilation *comp = cg->comp();
66
int i = 0;
67
bool is32bitLinux = false;
68
69
_properties._properties = 0;
70
_properties._registerFlags[TR::RealRegister::NoReg] = 0;
71
_properties._registerFlags[TR::RealRegister::gr0] = 0;
72
_properties._registerFlags[TR::RealRegister::gr1] = Preserved|PPC_Reserved; // system sp
73
74
// gr2 is Preserved in 32-bit Linux
75
if (comp->target().is64Bit())
76
{
77
_properties._registerFlags[TR::RealRegister::gr2] = 0;
78
}
79
else
80
{
81
if (comp->target().isAIX())
82
{
83
_properties._registerFlags[TR::RealRegister::gr2] = 0;
84
}
85
else if (comp->target().isLinux())
86
{
87
_properties._registerFlags[TR::RealRegister::gr2] = Preserved|PPC_Reserved;
88
is32bitLinux = true;
89
}
90
else
91
{
92
TR_ASSERT(0, "unsupported target");
93
}
94
}
95
96
_properties._registerFlags[TR::RealRegister::gr3] = IntegerReturn|IntegerArgument;
97
98
if (comp->target().is64Bit())
99
_properties._registerFlags[TR::RealRegister::gr4] = IntegerArgument;
100
else
101
_properties._registerFlags[TR::RealRegister::gr4] = IntegerReturn|IntegerArgument;
102
103
_properties._registerFlags[TR::RealRegister::gr5] = IntegerArgument;
104
_properties._registerFlags[TR::RealRegister::gr6] = IntegerArgument;
105
_properties._registerFlags[TR::RealRegister::gr7] = IntegerArgument;
106
_properties._registerFlags[TR::RealRegister::gr8] = IntegerArgument;
107
_properties._registerFlags[TR::RealRegister::gr9] = IntegerArgument;
108
_properties._registerFlags[TR::RealRegister::gr10] = IntegerArgument;
109
_properties._registerFlags[TR::RealRegister::gr11] = 0;
110
_properties._registerFlags[TR::RealRegister::gr12] = 0;
111
_properties._registerFlags[TR::RealRegister::gr13] = Preserved|PPC_Reserved; // meta data for 32bit, system for 64bit;
112
_properties._registerFlags[TR::RealRegister::gr14] = Preserved|PPC_Reserved; // J9 sp
113
if (comp->target().is64Bit())
114
{
115
_properties._registerFlags[TR::RealRegister::gr15] = Preserved|PPC_Reserved; // meta data
116
if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10))
117
_properties._registerFlags[TR::RealRegister::gr16] = Preserved; // typical preserved reg
118
else
119
_properties._registerFlags[TR::RealRegister::gr16] = Preserved|PPC_Reserved; // JTOC
120
}
121
else
122
{
123
_properties._registerFlags[TR::RealRegister::gr15] = Preserved;
124
_properties._registerFlags[TR::RealRegister::gr16] = Preserved;
125
}
126
127
for (i = TR::RealRegister::gr17; i <= TR::RealRegister::LastGPR; i++)
128
_properties._registerFlags[i] = Preserved; // gr17 - gr31 preserved
129
130
_properties._registerFlags[TR::RealRegister::fp0] = FloatReturn|FloatArgument;
131
_properties._registerFlags[TR::RealRegister::fp1] = FloatArgument;
132
_properties._registerFlags[TR::RealRegister::fp2] = FloatArgument;
133
_properties._registerFlags[TR::RealRegister::fp3] = FloatArgument;
134
_properties._registerFlags[TR::RealRegister::fp4] = FloatArgument;
135
_properties._registerFlags[TR::RealRegister::fp5] = FloatArgument;
136
_properties._registerFlags[TR::RealRegister::fp6] = FloatArgument;
137
_properties._registerFlags[TR::RealRegister::fp7] = FloatArgument;
138
139
for (i = TR::RealRegister::fp8; i <= TR::RealRegister::LastFPR; i++)
140
_properties._registerFlags[i] = 0; // fp8 - fp31 volatile
141
142
for (i = TR::RealRegister::vsr32; i <= TR::RealRegister::LastVSR; i++)
143
_properties._registerFlags[i] = 0; // vsr32 - vsr63 volatile
144
145
for (i = TR::RealRegister::FirstCCR; i <= TR::RealRegister::LastCCR; i++)
146
_properties._registerFlags[i] = 0; // cr0 - cr7 volatile
147
148
_properties._numIntegerArgumentRegisters = 8;
149
_properties._firstIntegerArgumentRegister = 0;
150
_properties._numFloatArgumentRegisters = 8;
151
_properties._firstFloatArgumentRegister = 8;
152
153
_properties._argumentRegisters[0] = TR::RealRegister::gr3;
154
_properties._argumentRegisters[1] = TR::RealRegister::gr4;
155
_properties._argumentRegisters[2] = TR::RealRegister::gr5;
156
_properties._argumentRegisters[3] = TR::RealRegister::gr6;
157
_properties._argumentRegisters[4] = TR::RealRegister::gr7;
158
_properties._argumentRegisters[5] = TR::RealRegister::gr8;
159
_properties._argumentRegisters[6] = TR::RealRegister::gr9;
160
_properties._argumentRegisters[7] = TR::RealRegister::gr10;
161
_properties._argumentRegisters[8] = TR::RealRegister::fp0;
162
_properties._argumentRegisters[9] = TR::RealRegister::fp1;
163
_properties._argumentRegisters[10] = TR::RealRegister::fp2;
164
_properties._argumentRegisters[11] = TR::RealRegister::fp3;
165
_properties._argumentRegisters[12] = TR::RealRegister::fp4;
166
_properties._argumentRegisters[13] = TR::RealRegister::fp5;
167
_properties._argumentRegisters[14] = TR::RealRegister::fp6;
168
_properties._argumentRegisters[15] = TR::RealRegister::fp7;
169
170
_properties._firstIntegerReturnRegister = 0;
171
_properties._returnRegisters[0] = TR::RealRegister::gr3;
172
173
if (comp->target().is64Bit())
174
{
175
_properties._firstFloatReturnRegister = 1;
176
_properties._returnRegisters[1] = TR::RealRegister::fp0;
177
178
if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10))
179
{
180
_properties._numAllocatableIntegerRegisters = 28; // 64 post-P10
181
_properties._firstAllocatableFloatArgumentRegister = 41; // 64 post-P10
182
_properties._lastAllocatableFloatVolatileRegister = 59; // 64 post-P10
183
}
184
else
185
{
186
_properties._numAllocatableIntegerRegisters = 27; // 64 pre-P10
187
_properties._firstAllocatableFloatArgumentRegister = 40; // 64 pre-P10
188
_properties._lastAllocatableFloatVolatileRegister = 58; // 64 pre-P10
189
}
190
}
191
else
192
{
193
_properties._firstFloatReturnRegister = 2;
194
_properties._returnRegisters[1] = TR::RealRegister::gr4;
195
_properties._returnRegisters[2] = TR::RealRegister::fp0;
196
197
if (is32bitLinux)
198
{
199
_properties._numAllocatableIntegerRegisters = 28; // 32 linux
200
_properties._firstAllocatableFloatArgumentRegister = 41; // 32 linux
201
_properties._lastAllocatableFloatVolatileRegister = 59; // 32 linux
202
}
203
else
204
{
205
_properties._numAllocatableIntegerRegisters = 29; // 32 non-linux
206
_properties._firstAllocatableFloatArgumentRegister = 42; // 32 non-linux
207
_properties._lastAllocatableFloatVolatileRegister = 60; // 32 non-linux
208
}
209
}
210
211
if (is32bitLinux)
212
{
213
_properties._firstAllocatableIntegerArgumentRegister = 8;
214
_properties._lastAllocatableIntegerVolatileRegister = 10;
215
}
216
else
217
{
218
_properties._firstAllocatableIntegerArgumentRegister = 9;
219
_properties._lastAllocatableIntegerVolatileRegister = 11;
220
}
221
_properties._numAllocatableFloatRegisters = 32;
222
_properties._numAllocatableVectorRegisters = 32;
223
_properties._numAllocatableCCRegisters = 8;
224
225
i = 0;
226
if (!is32bitLinux)
227
_properties._allocationOrder[i++] = TR::RealRegister::gr2;
228
_properties._allocationOrder[i++] = TR::RealRegister::gr12;
229
_properties._allocationOrder[i++] = TR::RealRegister::gr10;
230
_properties._allocationOrder[i++] = TR::RealRegister::gr9;
231
_properties._allocationOrder[i++] = TR::RealRegister::gr8;
232
_properties._allocationOrder[i++] = TR::RealRegister::gr7;
233
_properties._allocationOrder[i++] = TR::RealRegister::gr6;
234
_properties._allocationOrder[i++] = TR::RealRegister::gr5;
235
_properties._allocationOrder[i++] = TR::RealRegister::gr4;
236
_properties._allocationOrder[i++] = TR::RealRegister::gr3;
237
_properties._allocationOrder[i++] = TR::RealRegister::gr11;
238
_properties._allocationOrder[i++] = TR::RealRegister::gr0;
239
_properties._allocationOrder[i++] = TR::RealRegister::gr31;
240
_properties._allocationOrder[i++] = TR::RealRegister::gr30;
241
_properties._allocationOrder[i++] = TR::RealRegister::gr29;
242
_properties._allocationOrder[i++] = TR::RealRegister::gr28;
243
_properties._allocationOrder[i++] = TR::RealRegister::gr27;
244
_properties._allocationOrder[i++] = TR::RealRegister::gr26;
245
_properties._allocationOrder[i++] = TR::RealRegister::gr25;
246
_properties._allocationOrder[i++] = TR::RealRegister::gr24;
247
_properties._allocationOrder[i++] = TR::RealRegister::gr23;
248
_properties._allocationOrder[i++] = TR::RealRegister::gr22;
249
_properties._allocationOrder[i++] = TR::RealRegister::gr21;
250
_properties._allocationOrder[i++] = TR::RealRegister::gr20;
251
_properties._allocationOrder[i++] = TR::RealRegister::gr19;
252
_properties._allocationOrder[i++] = TR::RealRegister::gr18;
253
_properties._allocationOrder[i++] = TR::RealRegister::gr17;
254
255
if (comp->target().is64Bit())
256
{
257
if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10))
258
_properties._allocationOrder[i++] = TR::RealRegister::gr16;
259
}
260
else
261
{
262
_properties._allocationOrder[i++] = TR::RealRegister::gr16;
263
_properties._allocationOrder[i++] = TR::RealRegister::gr15;
264
}
265
266
_properties._allocationOrder[i++] = TR::RealRegister::fp13;
267
_properties._allocationOrder[i++] = TR::RealRegister::fp12;
268
_properties._allocationOrder[i++] = TR::RealRegister::fp11;
269
_properties._allocationOrder[i++] = TR::RealRegister::fp10;
270
_properties._allocationOrder[i++] = TR::RealRegister::fp9;
271
_properties._allocationOrder[i++] = TR::RealRegister::fp8;
272
_properties._allocationOrder[i++] = TR::RealRegister::fp7;
273
_properties._allocationOrder[i++] = TR::RealRegister::fp6;
274
_properties._allocationOrder[i++] = TR::RealRegister::fp5;
275
_properties._allocationOrder[i++] = TR::RealRegister::fp4;
276
_properties._allocationOrder[i++] = TR::RealRegister::fp3;
277
_properties._allocationOrder[i++] = TR::RealRegister::fp2;
278
_properties._allocationOrder[i++] = TR::RealRegister::fp1;
279
_properties._allocationOrder[i++] = TR::RealRegister::fp0;
280
_properties._allocationOrder[i++] = TR::RealRegister::fp31;
281
_properties._allocationOrder[i++] = TR::RealRegister::fp30;
282
_properties._allocationOrder[i++] = TR::RealRegister::fp29;
283
_properties._allocationOrder[i++] = TR::RealRegister::fp28;
284
_properties._allocationOrder[i++] = TR::RealRegister::fp27;
285
_properties._allocationOrder[i++] = TR::RealRegister::fp26;
286
_properties._allocationOrder[i++] = TR::RealRegister::fp25;
287
_properties._allocationOrder[i++] = TR::RealRegister::fp24;
288
_properties._allocationOrder[i++] = TR::RealRegister::fp23;
289
_properties._allocationOrder[i++] = TR::RealRegister::fp22;
290
_properties._allocationOrder[i++] = TR::RealRegister::fp21;
291
_properties._allocationOrder[i++] = TR::RealRegister::fp20;
292
_properties._allocationOrder[i++] = TR::RealRegister::fp19;
293
_properties._allocationOrder[i++] = TR::RealRegister::fp18;
294
_properties._allocationOrder[i++] = TR::RealRegister::fp17;
295
_properties._allocationOrder[i++] = TR::RealRegister::fp16;
296
_properties._allocationOrder[i++] = TR::RealRegister::fp15;
297
_properties._allocationOrder[i++] = TR::RealRegister::fp14;
298
299
_properties._allocationOrder[i++] = TR::RealRegister::vsr32;
300
_properties._allocationOrder[i++] = TR::RealRegister::vsr33;
301
_properties._allocationOrder[i++] = TR::RealRegister::vsr34;
302
_properties._allocationOrder[i++] = TR::RealRegister::vsr35;
303
_properties._allocationOrder[i++] = TR::RealRegister::vsr36;
304
_properties._allocationOrder[i++] = TR::RealRegister::vsr37;
305
_properties._allocationOrder[i++] = TR::RealRegister::vsr38;
306
_properties._allocationOrder[i++] = TR::RealRegister::vsr39;
307
_properties._allocationOrder[i++] = TR::RealRegister::vsr40;
308
_properties._allocationOrder[i++] = TR::RealRegister::vsr41;
309
_properties._allocationOrder[i++] = TR::RealRegister::vsr42;
310
_properties._allocationOrder[i++] = TR::RealRegister::vsr43;
311
_properties._allocationOrder[i++] = TR::RealRegister::vsr44;
312
_properties._allocationOrder[i++] = TR::RealRegister::vsr45;
313
_properties._allocationOrder[i++] = TR::RealRegister::vsr46;
314
_properties._allocationOrder[i++] = TR::RealRegister::vsr47;
315
_properties._allocationOrder[i++] = TR::RealRegister::vsr48;
316
_properties._allocationOrder[i++] = TR::RealRegister::vsr49;
317
_properties._allocationOrder[i++] = TR::RealRegister::vsr50;
318
_properties._allocationOrder[i++] = TR::RealRegister::vsr51;
319
_properties._allocationOrder[i++] = TR::RealRegister::vsr52;
320
_properties._allocationOrder[i++] = TR::RealRegister::vsr53;
321
_properties._allocationOrder[i++] = TR::RealRegister::vsr54;
322
_properties._allocationOrder[i++] = TR::RealRegister::vsr55;
323
_properties._allocationOrder[i++] = TR::RealRegister::vsr56;
324
_properties._allocationOrder[i++] = TR::RealRegister::vsr57;
325
_properties._allocationOrder[i++] = TR::RealRegister::vsr58;
326
_properties._allocationOrder[i++] = TR::RealRegister::vsr59;
327
_properties._allocationOrder[i++] = TR::RealRegister::vsr60;
328
_properties._allocationOrder[i++] = TR::RealRegister::vsr61;
329
_properties._allocationOrder[i++] = TR::RealRegister::vsr62;
330
_properties._allocationOrder[i++] = TR::RealRegister::vsr63;
331
332
_properties._allocationOrder[i++] = TR::RealRegister::cr7;
333
_properties._allocationOrder[i++] = TR::RealRegister::cr6;
334
_properties._allocationOrder[i++] = TR::RealRegister::cr5;
335
_properties._allocationOrder[i++] = TR::RealRegister::cr1;
336
_properties._allocationOrder[i++] = TR::RealRegister::cr0;
337
_properties._allocationOrder[i++] = TR::RealRegister::cr2;
338
_properties._allocationOrder[i++] = TR::RealRegister::cr3;
339
_properties._allocationOrder[i++] = TR::RealRegister::cr4;
340
341
if (comp->target().is64Bit())
342
{
343
if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10))
344
_properties._preservedRegisterMapForGC = 0x0000ffff;
345
else
346
_properties._preservedRegisterMapForGC = 0x00007fff;
347
_properties._methodMetaDataRegister = TR::RealRegister::gr15;
348
_properties._normalStackPointerRegister = TR::RealRegister::gr14;
349
_properties._alternateStackPointerRegister = TR::RealRegister::NoReg;
350
_properties._TOCBaseRegister = TR::RealRegister::gr16;
351
// Volatile GPR (0,2-12) + FPR (0-31) + CCR (0-7) + VR (0-31)
352
_properties._numberOfDependencyGPRegisters = 12 + 32 + 8 + 32;
353
setOffsetToFirstParm(0);
354
_properties._offsetToFirstLocal = -8;
355
}
356
else
357
{
358
_properties._preservedRegisterMapForGC = 0x0001ffff;
359
_properties._methodMetaDataRegister = TR::RealRegister::gr13;
360
_properties._normalStackPointerRegister = TR::RealRegister::gr14;
361
_properties._alternateStackPointerRegister = TR::RealRegister::NoReg;
362
_properties._TOCBaseRegister = TR::RealRegister::NoReg;
363
if (is32bitLinux)
364
// Volatile GPR (0,3-12) + FPR (0-31) + CCR (0-7) + VR (0-31)
365
_properties._numberOfDependencyGPRegisters = 11 + 32 + 8 + 32;
366
else
367
// Volatile GPR (0,2-12) + FPR (0-31) + CCR (0-7) + VR (0-31)
368
_properties._numberOfDependencyGPRegisters = 12 + 32 + 8 + 32;
369
setOffsetToFirstParm(0);
370
_properties._offsetToFirstLocal = -4;
371
}
372
_properties._computedCallTargetRegister = TR::RealRegister::gr0; // gr11 = interface, gr12 = virtual, so we need something else for computed
373
_properties._vtableIndexArgumentRegister = TR::RealRegister::gr12;
374
_properties._j9methodArgumentRegister = TR::RealRegister::gr3; // TODO:JSR292: Confirm
375
}
376
377
const TR::PPCLinkageProperties& J9::Power::PrivateLinkage::getProperties()
378
{
379
return _properties;
380
}
381
382
void J9::Power::PrivateLinkage::initPPCRealRegisterLinkage()
383
{
384
TR::Machine *machine = cg()->machine();
385
const TR::PPCLinkageProperties &linkage = getProperties();
386
int icount, ret_count=0, lockedGPRs = 0;
387
388
for (icount=TR::RealRegister::FirstGPR; icount<=TR::RealRegister::gr12;
389
icount++)
390
{
391
if (linkage.getReserved((TR::RealRegister::RegNum)icount))
392
{
393
machine->getRealRegister((TR::RealRegister::RegNum)icount)->setState(TR::RealRegister::Locked);
394
++lockedGPRs;
395
machine->getRealRegister((TR::RealRegister::RegNum)icount)->setAssignedRegister(machine->getRealRegister((TR::RealRegister::RegNum)icount));
396
}
397
else
398
{
399
int weight;
400
if (linkage.getIntegerReturn((TR::RealRegister::RegNum)icount))
401
{
402
weight = ++ret_count;
403
}
404
else
405
{
406
if (icount < TR::RealRegister::gr3)
407
{
408
weight = 2 + icount;
409
}
410
else
411
{
412
weight = icount;
413
}
414
}
415
machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(weight);
416
}
417
}
418
419
for (icount=TR::RealRegister::LastGPR;
420
icount>=TR::RealRegister::gr13; icount--)
421
{
422
if (linkage.getReserved((TR::RealRegister::RegNum)icount))
423
{
424
machine->getRealRegister((TR::RealRegister::RegNum)icount)->setState(TR::RealRegister::Locked);
425
++lockedGPRs;
426
machine->getRealRegister((TR::RealRegister::RegNum)icount)->setAssignedRegister(machine->getRealRegister((TR::RealRegister::RegNum)icount));
427
}
428
machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(0xf000-icount);
429
}
430
431
int lowestFPRWeight = TR::RealRegister::FirstFPR;
432
433
for (icount=TR::RealRegister::FirstFPR;
434
icount<=TR::RealRegister::LastFPR; icount++)
435
{
436
if (linkage.getPreserved((TR::RealRegister::RegNum)icount))
437
{
438
machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(0xf000-icount);
439
}
440
else
441
{
442
machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(lowestFPRWeight);
443
}
444
}
445
446
for (icount=TR::RealRegister::FirstVRF;
447
icount<=TR::RealRegister::LastVRF; icount++)
448
{
449
if (linkage.getPreserved((TR::RealRegister::RegNum)icount))
450
{
451
machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(0xf000-icount);
452
}
453
else
454
{
455
machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(icount);
456
}
457
}
458
459
for (icount=TR::RealRegister::FirstCCR;
460
icount<=TR::RealRegister::LastCCR; icount++)
461
{
462
if (linkage.getPreserved((TR::RealRegister::RegNum)icount))
463
{
464
machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(0xf000-icount);
465
}
466
else
467
{
468
machine->getRealRegister((TR::RealRegister::RegNum)icount)->setWeight(icount);
469
}
470
}
471
472
machine->setNumberOfLockedRegisters(TR_GPR, lockedGPRs);
473
machine->setNumberOfLockedRegisters(TR_FPR, 0);
474
machine->setNumberOfLockedRegisters(TR_VRF, 0);
475
}
476
477
uint32_t J9::Power::PrivateLinkage::getRightToLeft()
478
{
479
return getProperties().getRightToLeft();
480
}
481
482
void J9::Power::PrivateLinkage::mapStack(TR::ResolvedMethodSymbol *method)
483
{
484
ListIterator<TR::AutomaticSymbol> automaticIterator(&method->getAutomaticList());
485
TR::AutomaticSymbol *localCursor = automaticIterator.getFirst();
486
const TR::PPCLinkageProperties& linkage = getProperties();
487
TR::RealRegister::RegNum regIndex;
488
int32_t firstLocalOffset = linkage.getOffsetToFirstLocal();
489
uint32_t stackIndex = firstLocalOffset;
490
int32_t lowGCOffset = stackIndex;
491
TR::GCStackAtlas *atlas = cg()->getStackAtlas();
492
int32_t firstLocalGCIndex = atlas->getNumberOfParmSlotsMapped();
493
494
// map all garbage collected references together so can concisely represent
495
// stack maps. They must be mapped so that the GC map index in each local
496
// symbol is honoured.
497
498
uint32_t numberOfLocalSlotsMapped = atlas->getNumberOfSlotsMapped() - atlas->getNumberOfParmSlotsMapped();
499
500
stackIndex -= numberOfLocalSlotsMapped * TR::Compiler->om.sizeofReferenceAddress();
501
502
if (comp()->useCompressedPointers())
503
{
504
// If we have any local objects we have to make sure they're aligned properly when compressed pointers are used,
505
// otherwise pointer compression may clobber part of the pointer.
506
// Each auto's GC index will have already been aligned, we just need to make sure
507
// we align the starting stack offset.
508
uint32_t unalignedStackIndex = stackIndex;
509
stackIndex &= ~(TR::Compiler->om.getObjectAlignmentInBytes() - 1);
510
uint32_t paddingBytes = unalignedStackIndex - stackIndex;
511
if (paddingBytes > 0)
512
{
513
TR_ASSERT((paddingBytes & (TR::Compiler->om.sizeofReferenceAddress() - 1)) == 0, "Padding bytes should be a multiple of the slot/pointer size");
514
uint32_t paddingSlots = paddingBytes / TR::Compiler->om.sizeofReferenceAddress();
515
atlas->setNumberOfSlotsMapped(atlas->getNumberOfSlotsMapped() + paddingSlots);
516
}
517
}
518
519
// Map local references again to set the stack position correct according to
520
// the GC map index.
521
//
522
for (localCursor = automaticIterator.getFirst(); localCursor; localCursor = automaticIterator.getNext())
523
{
524
if (localCursor->getGCMapIndex() >= 0)
525
{
526
localCursor->setOffset(stackIndex + TR::Compiler->om.sizeofReferenceAddress() * (localCursor->getGCMapIndex() - firstLocalGCIndex));
527
if (localCursor->getGCMapIndex() == atlas->getIndexOfFirstInternalPointer())
528
{
529
atlas->setOffsetOfFirstInternalPointer(localCursor->getOffset() - firstLocalOffset);
530
}
531
}
532
}
533
534
method->setObjectTempSlots((lowGCOffset - stackIndex) / TR::Compiler->om.sizeofReferenceAddress());
535
lowGCOffset = stackIndex;
536
537
// Now map the rest of the locals
538
//
539
automaticIterator.reset();
540
localCursor = automaticIterator.getFirst();
541
542
while (localCursor != NULL)
543
{
544
if (comp()->target().is64Bit())
545
{
546
if (localCursor->getGCMapIndex() < 0 &&
547
localCursor->getSize() != 8)
548
{
549
mapSingleAutomatic(localCursor, stackIndex);
550
}
551
}
552
else
553
{
554
if (localCursor->getGCMapIndex() < 0 &&
555
localCursor->getDataType() != TR::Double)
556
{
557
mapSingleAutomatic(localCursor, stackIndex);
558
}
559
}
560
localCursor = automaticIterator.getNext();
561
}
562
563
automaticIterator.reset();
564
localCursor = automaticIterator.getFirst();
565
566
while (localCursor != NULL)
567
{
568
if (comp()->target().is64Bit())
569
{
570
if (localCursor->getGCMapIndex() < 0 &&
571
localCursor->getSize() == 8)
572
{
573
stackIndex -= (stackIndex & 0x4)?4:0;
574
mapSingleAutomatic(localCursor, stackIndex);
575
}
576
}
577
else
578
{
579
if (localCursor->getGCMapIndex() < 0 &&
580
localCursor->getDataType() == TR::Double)
581
{
582
stackIndex -= (stackIndex & 0x4)?4:0;
583
mapSingleAutomatic(localCursor, stackIndex);
584
}
585
}
586
localCursor = automaticIterator.getNext();
587
}
588
method->setLocalMappingCursor(stackIndex);
589
590
mapIncomingParms(method);
591
592
atlas->setLocalBaseOffset(lowGCOffset - firstLocalOffset);
593
atlas->setParmBaseOffset(atlas->getParmBaseOffset() + getOffsetToFirstParm() - firstLocalOffset);
594
}
595
596
void J9::Power::PrivateLinkage::mapSingleAutomatic(TR::AutomaticSymbol *p, uint32_t &stackIndex)
597
{
598
int32_t roundup = (comp()->useCompressedPointers() && p->isLocalObject() ? TR::Compiler->om.getObjectAlignmentInBytes() : TR::Compiler->om.sizeofReferenceAddress()) - 1;
599
int32_t roundedSize = (p->getSize() + roundup) & (~roundup);
600
if (roundedSize == 0)
601
roundedSize = 4;
602
603
p->setOffset(stackIndex -= roundedSize);
604
}
605
606
void J9::Power::PrivateLinkage::setParameterLinkageRegisterIndex(TR::ResolvedMethodSymbol *method)
607
{
608
ListIterator<TR::ParameterSymbol> paramIterator(&(method->getParameterList()));
609
TR::ParameterSymbol *paramCursor = paramIterator.getFirst();
610
int32_t numIntArgs = 0, numFloatArgs = 0;
611
const TR::PPCLinkageProperties& properties = getProperties();
612
613
while ( (paramCursor!=NULL) &&
614
( (numIntArgs < properties.getNumIntArgRegs()) ||
615
(numFloatArgs < properties.getNumFloatArgRegs()) ) )
616
{
617
int32_t index = -1;
618
619
switch (paramCursor->getDataType())
620
{
621
case TR::Int8:
622
case TR::Int16:
623
case TR::Int32:
624
case TR::Address:
625
if (numIntArgs<properties.getNumIntArgRegs())
626
{
627
index = numIntArgs;
628
}
629
numIntArgs++;
630
break;
631
case TR::Int64:
632
if (numIntArgs<properties.getNumIntArgRegs())
633
{
634
index = numIntArgs;
635
}
636
if (comp()->target().is64Bit())
637
numIntArgs ++;
638
else
639
numIntArgs += 2;
640
break;
641
case TR::Float:
642
case TR::Double:
643
if (numFloatArgs<properties.getNumFloatArgRegs())
644
{
645
index = numFloatArgs;
646
}
647
numFloatArgs++;
648
break;
649
}
650
paramCursor->setLinkageRegisterIndex(index);
651
paramCursor = paramIterator.getNext();
652
}
653
}
654
655
bool J9::Power::PrivateLinkage::hasToBeOnStack(TR::ParameterSymbol *parm)
656
{
657
TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol();
658
TR_OpaqueClassBlock *throwableClass;
659
660
/* Defect 138664: All synchronized methods can potentially throw an
661
IllegalMonitorState exception so we must always save the this pointer on
662
to the stack so the exception handler can unlock the object. Also,
663
hasCall() does not consider jitNewObject() calls so an OOM exception could
664
be thrown even when hasCall() returns false */
665
666
TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());
667
668
bool result = (parm->getAssignedGlobalRegisterIndex()>=0 &&
669
( ( parm->getLinkageRegisterIndex()==0 &&
670
parm->isCollectedReference() &&
671
!bodySymbol->isStatic() &&
672
( ( bodySymbol->isSynchronised()
673
) ||
674
(
675
!strncmp(bodySymbol->getResolvedMethod()->nameChars(), "<init>", 6) &&
676
( (throwableClass = fej9->getClassFromSignature("Ljava/lang/Throwable;", 21, bodySymbol->getResolvedMethod())) == 0 ||
677
fej9->isInstanceOf(bodySymbol->getResolvedMethod()->containingClass(), throwableClass, true) != TR_no
678
)
679
)
680
)
681
) ||
682
parm->isParmHasToBeOnStack()
683
)
684
);
685
686
// Problem Report 96788:
687
//
688
// There is a potential race condition here. Because of the query to the frontend this function could
689
// possibly return different results at different points in the compilation dependent on whether the
690
// java/lang/Throwable class is resolved or not. This is a problem because this query is used to
691
// determine whether we need to generate a GC map for this parameter and whether we need to generate
692
// a store out to the stack for this parameter. Because these two queries happen at two different points
693
// in the compilation we could encounter a situation where we generate a GC map for this parameter but
694
// not generate a store out to the stack. This causes assertions in the VM if we hit a GC point in this
695
// compilation unit. To avoid this issue we cache the result of this function and directly modify the
696
// parameter symbol.
697
698
// TODO : Where does the java/lang/Throwable code below originate and why is it here? This seems like
699
// a very hacky fix to a very specific problem. Also why is this code not commoned up with Z and why
700
// is it missing for X?
701
702
if (result)
703
parm->setParmHasToBeOnStack();
704
705
return result;
706
}
707
708
static TR::Instruction *unrollPrologueInitLoop(TR::CodeGenerator *cg, TR::Node *node, int32_t num, int32_t initSlotOffset, TR::Register *nullReg,
709
TR::RealRegister *gr11, TR::RealRegister *baseInitReg, TR::RealRegister *gr12, TR::RealRegister *cr0, TR::LabelSymbol *loopLabel,
710
TR::Instruction *cursor)
711
{
712
TR_HeapMemory trHeapMemory = cg->trMemory();
713
int32_t wordsToUnroll = num;
714
TR::Compilation *comp = cg->comp();
715
716
static bool disableVSXMemInit = (feGetEnv("TR_disableVSXMemInit") != NULL); //Disable toggle incase we break in production.
717
bool use8Bytes = ((cg->is64BitProcessor() && TR::Compiler->om.sizeofReferenceAddress() == 4) || TR::Compiler->om.sizeofReferenceAddress() == 8);
718
bool useVectorStores = (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P8) && comp->target().cpu.supportsFeature(OMR_FEATURE_PPC_HAS_VSX) && !disableVSXMemInit);
719
720
if (useVectorStores)
721
{
722
int32_t wordsUnrolledPerIteration = (128 * 4) / (TR::Compiler->om.sizeofReferenceAddress() * 8); // (number of bits cleared by one iteration using 4 stxvw4x) / (number of bits per word i.e. bits in a java pointer)
723
if (wordsToUnroll >= wordsUnrolledPerIteration)
724
{
725
TR::RealRegister *vectorNullReg = cg->machine()->getRealRegister(TR::RealRegister::vr0);
726
cursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::xxlxor, node, vectorNullReg, vectorNullReg, vectorNullReg, cursor);
727
728
int32_t loopIterations = wordsToUnroll / wordsUnrolledPerIteration;
729
wordsToUnroll = wordsToUnroll % wordsUnrolledPerIteration;
730
731
TR_ASSERT_FATAL( initSlotOffset <= UPPER_IMMED, "initSlotOffset (%d) is too big to fit in a signed immediate field", initSlotOffset);
732
cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, gr12, baseInitReg, initSlotOffset, cursor);
733
baseInitReg = gr12;
734
initSlotOffset = 0;
735
736
if (loopIterations > 1)
737
{
738
cursor = loadConstant(cg, node, loopIterations, gr11, cursor);
739
cursor = generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, gr11, 0, cursor);
740
cursor = loadConstant(cg, node, 16, gr11, cursor); // r11 is now free so we can use it for const 16 offset
741
cursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel, cursor);
742
}
743
else
744
{
745
cursor = loadConstant(cg, node, 16, gr11, cursor);
746
}
747
748
cursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stxvw4x, node, TR::MemoryReference::createWithIndexReg(cg, nullReg, baseInitReg, 16), vectorNullReg, cursor);
749
cursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stxvw4x, node, TR::MemoryReference::createWithIndexReg(cg, gr11 , baseInitReg, 16), vectorNullReg, cursor);
750
cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, baseInitReg, baseInitReg, 32, cursor);
751
cursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stxvw4x, node, TR::MemoryReference::createWithIndexReg(cg, nullReg, baseInitReg, 16), vectorNullReg, cursor);
752
cursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stxvw4x, node, TR::MemoryReference::createWithIndexReg(cg, gr11 , baseInitReg, 16), vectorNullReg, cursor);
753
754
if (loopIterations > 1)
755
{
756
cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, baseInitReg, baseInitReg, 32, cursor);
757
cursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bdnz, node, loopLabel, cr0, cursor);
758
}
759
else
760
{
761
initSlotOffset += 32; // if no loops needed, then no need to generate the addi when we can just increase the offset
762
}
763
}
764
765
if (use8Bytes && TR::Compiler->om.sizeofReferenceAddress() == 4)
766
{
767
// we only need to do half the work since we'll be using std to wipe two 32bit words
768
// NOTE: we need to do a stw at the end if this is odd since std only stores 8 bytes at a time
769
// (and we have 4 bytes leftover after the loop)
770
wordsToUnroll /= 2;
771
}
772
773
// unroll any remaining words
774
TR::InstOpCode::Mnemonic instruction = (use8Bytes ? TR::InstOpCode::std : TR::InstOpCode::stw);
775
int32_t storeSize = (use8Bytes ? 8 : 4);
776
while (wordsToUnroll > 0)
777
{
778
cursor = generateMemSrc1Instruction(cg, instruction, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset, storeSize), nullReg, cursor);
779
initSlotOffset += storeSize;
780
wordsToUnroll--;
781
}
782
783
// if we had an odd number of words to unroll with a 64bit arch, we need to add one more store to clear it
784
// (since we used store double word)
785
if ((use8Bytes && TR::Compiler->om.sizeofReferenceAddress() == 4) && (num % 2 == 1))
786
{
787
cursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset, 4), nullReg, cursor);
788
}
789
}
790
else
791
{
792
if (use8Bytes && TR::Compiler->om.sizeofReferenceAddress() == 4)
793
wordsToUnroll /= 2;
794
795
if (wordsToUnroll >=4)
796
{
797
if (wordsToUnroll >=8)
798
{
799
if(baseInitReg->getRegisterNumber()== TR::RealRegister::gr14)
800
{
801
cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, gr12,baseInitReg, 0 , cursor);
802
baseInitReg = gr12;
803
}
804
cursor = loadConstant(cg, node, (int32_t)(wordsToUnroll/4), gr11, cursor);
805
cursor = generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, gr11, 0, cursor);
806
cursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel, cursor);
807
}
808
// This clears (wordsToUnroll/4) * (use8Bytes ? 32: 16) bytes.
809
cursor = generateMemSrc1Instruction(cg, use8Bytes? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset, TR::Compiler->om.sizeofReferenceAddress()), nullReg, cursor);
810
cursor = generateMemSrc1Instruction(cg, use8Bytes? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset+(use8Bytes?8:4), TR::Compiler->om.sizeofReferenceAddress()), nullReg, cursor);
811
cursor = generateMemSrc1Instruction(cg, use8Bytes? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset+(use8Bytes?16:8), TR::Compiler->om.sizeofReferenceAddress()), nullReg, cursor);
812
cursor = generateMemSrc1Instruction(cg, use8Bytes? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset+(use8Bytes?24:12), TR::Compiler->om.sizeofReferenceAddress()), nullReg, cursor);
813
if (wordsToUnroll >=8)
814
{
815
cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, gr12, gr12, (use8Bytes?32:16), cursor);
816
cursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bdnz, node, loopLabel, cr0, cursor);
817
}
818
else
819
{
820
initSlotOffset += (use8Bytes?32:16);
821
}
822
}
823
// Clears ((use8Bytes ? 8 : 4)* (wordsToUnroll % 4)) bytes
824
switch (wordsToUnroll % 4)
825
{
826
case 3:
827
cursor = generateMemSrc1Instruction(cg, use8Bytes? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset+(use8Bytes?16:8), TR::Compiler->om.sizeofReferenceAddress()), nullReg, cursor);
828
case 2:
829
cursor = generateMemSrc1Instruction(cg, use8Bytes? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset+(use8Bytes?8:4), TR::Compiler->om.sizeofReferenceAddress()), nullReg, cursor);
830
case 1:
831
cursor = generateMemSrc1Instruction(cg, use8Bytes? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset, TR::Compiler->om.sizeofReferenceAddress()), nullReg, cursor);
832
break;
833
}
834
// Last one if needed
835
if (use8Bytes && TR::Compiler->om.sizeofReferenceAddress() == 4 && num % 2 == 1)
836
{
837
if (wordsToUnroll %4)
838
initSlotOffset += (use8Bytes?8:4)*(wordsToUnroll%4);
839
cursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, baseInitReg, initSlotOffset, TR::Compiler->om.sizeofReferenceAddress()), nullReg, cursor);
840
}
841
}
842
return cursor;
843
}
844
845
static int32_t calculateFrameSize(TR::RealRegister::RegNum &intSavedFirst,
846
int32_t &argSize,
847
int32_t &size,
848
int32_t &regSaveOffset,
849
int32_t &saveSize,
850
TR::CodeGenerator *cg,
851
bool &saveLR)
852
{
853
TR::Compilation *comp = cg->comp();
854
TR::Machine *machine = cg->machine();
855
TR::Linkage* linkage = cg->getLinkage(TR_Private);
856
const TR::PPCLinkageProperties& properties = cg->getProperties();
857
int32_t firstLocalOffset = properties.getOffsetToFirstLocal();
858
int32_t registerSaveDescription = 0;
859
860
// Currently no non-volatile FPR's in private linkage
861
// If we change the private linkage to add non-volatile FPR's or CCR's
862
// we should clean up this code to be independent of the linkage
863
// (ie, to test properties.getPreserved).
864
//
865
saveLR = (!cg->getSnippetList().empty() ||
866
comp->getJittedMethodSymbol()->isEHAware() ||
867
cg->canExceptByTrap() ||
868
machine->getLinkRegisterKilled());
869
870
if (0 && comp->target().is64Bit())
871
{
872
argSize = (cg->getLargestOutgoingArgSize() * 2) + linkage->getOffsetToFirstParm();
873
}
874
else
875
{
876
argSize = cg->getLargestOutgoingArgSize() + linkage->getOffsetToFirstParm();
877
}
878
879
while (intSavedFirst<=TR::RealRegister::LastGPR && !machine->getRealRegister(intSavedFirst)->getHasBeenAssignedInMethod())
880
intSavedFirst=(TR::RealRegister::RegNum)((uint32_t)intSavedFirst+1);
881
882
// the registerSaveDescription is emitted as follows:
883
// 0000 0000 0000 000 0 0000 0000 0000 0000
884
// <---- ---->
885
// 17 bits for saved GPRs (r15 - r32)
886
// so the first bit represents whether r15 is saved & so on
887
// <--- --->
888
// 15 bits to represent the save offset from bp
889
// allowing 2^15 bytes / 8 = 4096 locals in 64-bit
890
//
891
for (int32_t i = intSavedFirst; i <= TR::RealRegister::LastGPR; i++)
892
{
893
registerSaveDescription |= 1 << (i - TR::RealRegister::gr15);
894
}
895
896
// Currently no non-volatile FPR's in private linkage
897
898
saveSize += (TR::RealRegister::LastGPR - intSavedFirst + 1) * TR::Compiler->om.sizeofReferenceAddress();
899
900
size += saveSize+argSize;
901
if (!saveLR && size == -firstLocalOffset) // TODO: have a emptyFrame bool to be used throughout
902
{
903
TR_ASSERT(argSize==0, "Wrong descriptor setting");
904
size = 0;
905
cg->setFrameSizeInBytes(0);
906
}
907
else
908
{
909
//Align the stack frame
910
const uint32_t alignBytes = 16;
911
size = (size + (alignBytes - 1) & (~(alignBytes - 1)));
912
913
regSaveOffset = (size-argSize+firstLocalOffset);
914
915
//In MethodMetaData jitAddSpilledRegisters, we lookup the regSaveOffset
916
//which must match up to what we have here or else the stackwalker will
917
//run into errors.
918
//Fail the compilation if we overflow the 15 bits of regSaveOffset.
919
if(regSaveOffset > 0x7FFF || regSaveOffset < 0 )
920
{
921
//Fail if we underflow or overflow.
922
comp->failCompilation<TR::CompilationInterrupted>("Overflowed or underflowed bounds of regSaveOffset in calculateFrameSize.");
923
}
924
925
if (comp->getOption(TR_TraceCG))
926
traceMsg(comp, "PPCLinkage calculateFrameSize registerSaveDescription: 0x%x regSaveOffset: %x\n", registerSaveDescription, regSaveOffset);
927
registerSaveDescription |= (regSaveOffset << 17); // see above for details
928
cg->setFrameSizeInBytes(size+firstLocalOffset);
929
TR_ASSERT((size-argSize+firstLocalOffset)<2048*1024, "Descriptor overflowed.\n");
930
}
931
932
return registerSaveDescription;
933
}
934
935
void J9::Power::PrivateLinkage::createPrologue(TR::Instruction *cursor)
936
{
937
TR::Machine *machine = cg()->machine();
938
const TR::PPCLinkageProperties& properties = getProperties();
939
TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol();
940
TR::RealRegister *stackPtr = cg()->getStackPointerRegister();
941
TR::RealRegister *metaBase = cg()->getMethodMetaDataRegister();
942
TR::RealRegister *gr0 = machine->getRealRegister(TR::RealRegister::gr0);
943
TR::RealRegister *gr11 = machine->getRealRegister(TR::RealRegister::gr11);
944
TR::RealRegister *gr12 = machine->getRealRegister(TR::RealRegister::gr12);
945
TR::RealRegister *cr0 = machine->getRealRegister(TR::RealRegister::cr0);
946
TR::Node *firstNode = comp()->getStartTree()->getNode();
947
int32_t size = -(bodySymbol->getLocalMappingCursor());
948
int32_t residualSize, saveSize=0, argSize;
949
int32_t registerSaveDescription=0;
950
int32_t firstLocalOffset = properties.getOffsetToFirstLocal();
951
int i;
952
TR::RealRegister::RegNum intSavedFirst=TR::RealRegister::gr15;
953
TR::RealRegister::RegNum regIndex;
954
int32_t regSaveOffset = 0;
955
bool saveLR = false;
956
registerSaveDescription = calculateFrameSize(intSavedFirst, argSize, size, regSaveOffset, saveSize, cg(), saveLR);
957
958
cg()->setRegisterSaveDescription(registerSaveDescription);
959
residualSize = size;
960
961
if (comp()->getOption(TR_EntryBreakPoints))
962
{
963
cursor = generateInstruction(cg(), TR::InstOpCode::bad, firstNode, cursor);
964
}
965
966
bool fsd = comp()->getOption(TR_FullSpeedDebug);
967
968
// If in Full Speed Debug, the parameters have to be saved before the call to Stack Check
969
// and the stack map and register maps have to be updated accordingly
970
if (fsd)
971
{
972
// Only call saveArguments for pushing the parameters on the stack when we are on Full Speed Debug
973
cursor = saveArguments(cursor, fsd, true);
974
}
975
976
// Load the stack limit offset for comparison
977
if (!comp()->isDLT())
978
cursor = generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, firstNode, gr11,
979
TR::MemoryReference::createWithDisplacement(cg(), metaBase, cg()->getStackLimitOffset(),
980
TR::Compiler->om.sizeofReferenceAddress()), cursor);
981
982
if (cg()->getFrameSizeInBytes() || saveLR)
983
{
984
if ((cg()->getFrameSizeInBytes() + TR::Compiler->om.sizeofReferenceAddress()) > (-LOWER_IMMED))
985
{
986
// Large Frame Support
987
988
// gr12 <- (totalFrameSize + 1 slot)
989
cursor = loadConstant(cg(), firstNode, (int32_t)(cg()->getFrameSizeInBytes() + TR::Compiler->om.sizeofReferenceAddress()), gr12, cursor);
990
991
// javaSP <- javaSP - (totalFrameSize + 1 slot)
992
cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::subf, firstNode, stackPtr, gr12, stackPtr, cursor);
993
994
// gr12 == totalFrameSize
995
if (!comp()->isDLT())
996
cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addi2, firstNode, gr12, gr12, -TR::Compiler->om.sizeofReferenceAddress(), cursor);
997
998
if (saveLR)
999
{
1000
cursor = generateTrg1Instruction(cg(), TR::InstOpCode::mflr, firstNode, gr0, cursor);
1001
}
1002
1003
// Check for stack overflow (set a flag)
1004
if (!comp()->isDLT())
1005
cursor = generateTrg1Src2Instruction(cg(),TR::InstOpCode::Op_cmpl, firstNode, cr0, stackPtr, gr11, cursor);
1006
1007
if (saveLR)
1008
{
1009
// javaSP[totalFrameSize] <- linkRegister
1010
cursor = generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_stx, firstNode, TR::MemoryReference::createWithIndexReg(cg(), stackPtr, gr12, TR::Compiler->om.sizeofReferenceAddress()),
1011
gr0, cursor);
1012
}
1013
}
1014
else
1015
{
1016
// Small Frame Support
1017
1018
// javaSP <- javaSP - (totalFrameSize + 1 slot)
1019
cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addi2,
1020
firstNode, stackPtr, stackPtr, -(cg()->getFrameSizeInBytes() + TR::Compiler->om.sizeofReferenceAddress()), cursor);
1021
if (saveLR)
1022
{
1023
cursor = generateTrg1Instruction(cg(), TR::InstOpCode::mflr, firstNode, gr0, cursor);
1024
}
1025
1026
// Check for stack overflow (set a flag)
1027
if (!comp()->isDLT())
1028
cursor = generateTrg1Src2Instruction(cg(),TR::InstOpCode::Op_cmpl, firstNode, cr0, stackPtr, gr11, cursor);
1029
1030
if (saveLR)
1031
{
1032
// javaSP[totalFrameSize] <- linkRegister
1033
cursor = generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_st, firstNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, cg()->getFrameSizeInBytes(), TR::Compiler->om.sizeofReferenceAddress()),
1034
gr0, cursor);
1035
}
1036
}
1037
}
1038
else
1039
{
1040
// Empty Frame Support
1041
1042
// Check for stack overflow (set a flag)
1043
if (!comp()->isDLT())
1044
cursor = generateTrg1Src2Instruction(cg(),TR::InstOpCode::Op_cmpl, firstNode, cr0, stackPtr, gr11, cursor);
1045
}
1046
1047
if (!comp()->isDLT())
1048
{
1049
TR::LabelSymbol *snippetLabel = generateLabelSymbol(cg());
1050
TR::LabelSymbol *reStartLabel = generateLabelSymbol(cg());
1051
1052
// Branch to StackOverflow snippet if javaSP > stack limit
1053
if (comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_GP))
1054
// use PPC AS branch hint
1055
cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::ble, PPCOpProp_BranchUnlikely, firstNode, snippetLabel, cr0, cursor);
1056
else
1057
cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::ble, firstNode, snippetLabel, cr0, cursor);
1058
TR::Snippet *snippet = new (trHeapMemory()) TR::PPCStackCheckFailureSnippet(cg(), firstNode, reStartLabel, snippetLabel);
1059
cg()->addSnippet(snippet);
1060
cursor = generateLabelInstruction(cg(), TR::InstOpCode::label, firstNode, reStartLabel, cursor);
1061
}
1062
1063
if (intSavedFirst <= TR::RealRegister::LastGPR)
1064
{
1065
if (comp()->target().is64Bit() ||
1066
(TR::RealRegister::LastGPR - intSavedFirst <= 3))
1067
{
1068
for (regIndex=intSavedFirst; regIndex<=TR::RealRegister::LastGPR; regIndex=(TR::RealRegister::RegNum)((uint32_t)regIndex+1))
1069
{
1070
cursor = generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_st, firstNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, argSize, TR::Compiler->om.sizeofReferenceAddress()), machine->getRealRegister(regIndex), cursor);
1071
1072
argSize = argSize + TR::Compiler->om.sizeofReferenceAddress();
1073
}
1074
}
1075
else
1076
{
1077
cursor = generateMemSrc1Instruction(cg(), (intSavedFirst==TR::RealRegister::LastGPR)?TR::InstOpCode::stw:TR::InstOpCode::stmw, firstNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, argSize, 4*(TR::RealRegister::LastGPR-intSavedFirst+1)), machine->getRealRegister(intSavedFirst), cursor);
1078
1079
argSize += (TR::RealRegister::LastGPR - intSavedFirst + 1) * 4;
1080
}
1081
}
1082
1083
1084
TR::GCStackAtlas *atlas = cg()->getStackAtlas();
1085
if (atlas != NULL)
1086
{
1087
//
1088
// Note that since internal pointer support has been added, all pinning
1089
// array autos and derived internal pointer autos must be zero initialized
1090
// in prologue regardless of the liveness information. This is because
1091
// the stack walker/GC examine internal pointer related slots whenever GC
1092
// occurs. Having the slots in uninitialized state is not correct for GC.
1093
//
1094
uint32_t numLocalsToBeInitialized = atlas->getNumberOfSlotsToBeInitialized();
1095
if ((numLocalsToBeInitialized > 0) ||
1096
atlas->getInternalPointerMap())
1097
{
1098
bool adjustedFrameOnce = false;
1099
TR::RealRegister *nullValueRegister = gr0;
1100
int32_t offset = atlas->getLocalBaseOffset();
1101
1102
cursor = loadConstant(cg(), firstNode, NULLVALUE, nullValueRegister, cursor);
1103
1104
static bool disableUnrollPrologueInitLoop = (feGetEnv("TR_DisableUnrollPrologueInitLoop") != NULL);
1105
if (numLocalsToBeInitialized > 5)
1106
{
1107
int32_t loopDistance = -numLocalsToBeInitialized * TR::Compiler->om.sizeofReferenceAddress();
1108
int32_t initBottomOffset = offset - loopDistance;
1109
int32_t initSlotOffset =0;
1110
1111
TR_ASSERT(initBottomOffset<=0, "Initialized and internal pointer portion size doesn't make senses");
1112
if (residualSize >= -LOWER_IMMED)
1113
{
1114
cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::add, firstNode, gr12, gr12, stackPtr, cursor);
1115
adjustedFrameOnce = true;
1116
if (size == residualSize) // only happens when LR is not saved
1117
{
1118
residualSize -= TR::Compiler->om.sizeofReferenceAddress();
1119
initBottomOffset -= TR::Compiler->om.sizeofReferenceAddress();
1120
}
1121
1122
if (initBottomOffset < LOWER_IMMED)
1123
{
1124
if (0x00008000 == HI_VALUE(initBottomOffset))
1125
{
1126
cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addis, firstNode, gr12, gr12, 0x7FFF, cursor);
1127
cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addis, firstNode, gr12, gr12, 0x1, cursor);
1128
}
1129
else
1130
{
1131
cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addis, firstNode, gr12, gr12, HI_VALUE(initBottomOffset), cursor);
1132
}
1133
}
1134
1135
if (initBottomOffset & 0xFFFF)
1136
cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addi2, firstNode, gr12, gr12, LO_VALUE(initBottomOffset), cursor);
1137
}
1138
else
1139
{
1140
adjustedFrameOnce = true;
1141
if (size == residualSize) // only happens when LR is not saved
1142
residualSize -= TR::Compiler->om.sizeofReferenceAddress();
1143
initSlotOffset = initSlotOffset+ residualSize+initBottomOffset;
1144
}
1145
1146
TR::LabelSymbol *loopLabel = generateLabelSymbol(cg());
1147
if (!disableUnrollPrologueInitLoop)
1148
{
1149
initSlotOffset += loopDistance;
1150
if (residualSize >= -LOWER_IMMED)
1151
cursor = unrollPrologueInitLoop(cg(), firstNode, numLocalsToBeInitialized, loopDistance, nullValueRegister, gr11, gr12, gr12, cr0, loopLabel, cursor);
1152
else
1153
cursor = unrollPrologueInitLoop(cg(), firstNode, numLocalsToBeInitialized, initSlotOffset, nullValueRegister, gr11, stackPtr, gr12, cr0, loopLabel, cursor);
1154
}
1155
else
1156
{
1157
cursor = loadConstant(cg(), firstNode, loopDistance, gr11, cursor);
1158
cursor = generateLabelInstruction(cg(), TR::InstOpCode::label, firstNode, loopLabel, cursor);
1159
if (residualSize >= -LOWER_IMMED)
1160
cursor = generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_stx, firstNode, TR::MemoryReference::createWithIndexReg(cg(), gr12, gr11, TR::Compiler->om.sizeofReferenceAddress()), nullValueRegister, cursor);
1161
else
1162
cursor = generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_stx, firstNode, TR::MemoryReference::createWithIndexReg(cg(), stackPtr, gr11, initSlotOffset+ TR::Compiler->om.sizeofReferenceAddress()), nullValueRegister, cursor);
1163
cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addic_r, firstNode, gr11, gr11, cr0, TR::Compiler->om.sizeofReferenceAddress(), cursor);
1164
cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::bne, firstNode, loopLabel, cr0, cursor);
1165
}
1166
}
1167
else
1168
{
1169
adjustedFrameOnce = true;
1170
if (size == residualSize) // only happens when LR is not saved
1171
residualSize -= TR::Compiler->om.sizeofReferenceAddress();
1172
bool use8BytesOn32Bit = cg()->is64BitProcessor() && (TR::Compiler->om.sizeofReferenceAddress() == 4);
1173
if (!disableUnrollPrologueInitLoop && use8BytesOn32Bit)
1174
{
1175
int32_t count = 0;
1176
if (numLocalsToBeInitialized >= 2)
1177
{
1178
cursor = generateMemSrc1Instruction(cg(), TR::InstOpCode::std, firstNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, offset+residualSize, TR::Compiler->om.sizeofReferenceAddress()), nullValueRegister, cursor);
1179
count++;
1180
if (numLocalsToBeInitialized >= 4)
1181
{
1182
cursor = generateMemSrc1Instruction(cg(), TR::InstOpCode::std, firstNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, offset+residualSize+8, TR::Compiler->om.sizeofReferenceAddress()), nullValueRegister, cursor);
1183
count++;
1184
}
1185
}
1186
if (numLocalsToBeInitialized % 2 == 1)
1187
cursor = generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_st, firstNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, offset+residualSize+(count*8), TR::Compiler->om.sizeofReferenceAddress()), nullValueRegister, cursor);
1188
}
1189
else
1190
{
1191
for (i = 0; i < numLocalsToBeInitialized; i++, offset += TR::Compiler->om.sizeofReferenceAddress())
1192
{
1193
cursor = generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_st, firstNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, offset+residualSize, TR::Compiler->om.sizeofReferenceAddress()), nullValueRegister, cursor);
1194
}
1195
}
1196
}
1197
1198
if (atlas->getInternalPointerMap())
1199
{
1200
int32_t offset = atlas->getOffsetOfFirstInternalPointer();
1201
1202
// First collect all pinning arrays that are the base for at least
1203
// one derived internal pointer stack slot
1204
//
1205
int32_t numDistinctPinningArrays = 0;
1206
List<TR_InternalPointerPair> seenInternalPtrPairs(trMemory());
1207
List<TR::AutomaticSymbol> seenPinningArrays(trMemory());
1208
ListIterator<TR_InternalPointerPair> internalPtrIt(&atlas->getInternalPointerMap()->getInternalPointerPairs());
1209
for (TR_InternalPointerPair *internalPtrPair = internalPtrIt.getFirst(); internalPtrPair; internalPtrPair = internalPtrIt.getNext())
1210
{
1211
bool seenPinningArrayBefore = false;
1212
ListIterator<TR_InternalPointerPair> seenInternalPtrIt(&seenInternalPtrPairs);
1213
for (TR_InternalPointerPair *seenInternalPtrPair = seenInternalPtrIt.getFirst(); seenInternalPtrPair && (seenInternalPtrPair != internalPtrPair); seenInternalPtrPair = seenInternalPtrIt.getNext())
1214
{
1215
if (internalPtrPair->getPinningArrayPointer() == seenInternalPtrPair->getPinningArrayPointer())
1216
{
1217
seenPinningArrayBefore = true;
1218
break;
1219
}
1220
}
1221
1222
if (!seenPinningArrayBefore)
1223
{
1224
seenPinningArrays.add(internalPtrPair->getPinningArrayPointer());
1225
seenInternalPtrPairs.add(internalPtrPair);
1226
numDistinctPinningArrays++;
1227
}
1228
}
1229
1230
// Now collect all pinning arrays that are the base for only
1231
// internal pointers in registers
1232
//
1233
ListIterator<TR::AutomaticSymbol> autoIt(&atlas->getPinningArrayPtrsForInternalPtrRegs());
1234
TR::AutomaticSymbol *autoSymbol;
1235
for (autoSymbol = autoIt.getFirst(); autoSymbol != NULL; autoSymbol = autoIt.getNext())
1236
{
1237
if (!seenPinningArrays.find(autoSymbol))
1238
{
1239
seenPinningArrays.add(autoSymbol);
1240
numDistinctPinningArrays++;
1241
}
1242
}
1243
1244
// Total number of slots to be initialized is number of pinning arrays +
1245
// number of derived internal pointer stack slots
1246
//
1247
int32_t numSlotsToBeInitialized = numDistinctPinningArrays + atlas->getInternalPointerMap()->getNumInternalPointers();
1248
1249
if (!adjustedFrameOnce)
1250
{
1251
if (size == residualSize) // only happens when LR is not saved
1252
residualSize -= TR::Compiler->om.sizeofReferenceAddress();
1253
}
1254
if (!disableUnrollPrologueInitLoop)
1255
{
1256
TR::LabelSymbol *loopLabel = generateLabelSymbol(cg());
1257
cursor = unrollPrologueInitLoop(cg(), firstNode, numSlotsToBeInitialized, offset+residualSize, nullValueRegister, gr11, stackPtr, gr12, cr0, loopLabel, cursor);
1258
}
1259
else
1260
{
1261
for (i = 0; i < numSlotsToBeInitialized; i++, offset += TR::Compiler->om.sizeofReferenceAddress())
1262
{
1263
cursor = generateMemSrc1Instruction(cg(),TR::InstOpCode::Op_st, firstNode, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, offset+residualSize, TR::Compiler->om.sizeofReferenceAddress()), nullValueRegister, cursor);
1264
}
1265
}
1266
}
1267
}
1268
}
1269
1270
TR_ASSERT(size<=UPPER_IMMED-1032, "Setting up a frame pointer anyway.");
1271
ListIterator<TR::AutomaticSymbol> automaticIterator(&bodySymbol->getAutomaticList());
1272
TR::AutomaticSymbol *localCursor = automaticIterator.getFirst();
1273
1274
while (localCursor!=NULL)
1275
{
1276
TR_ASSERT(!comp()->useCompressedPointers() ||
1277
!localCursor->isLocalObject() ||
1278
!localCursor->isCollectedReference() ||
1279
(localCursor->getOffset() & (TR::Compiler->om.getObjectAlignmentInBytes() - 1)) == 0,
1280
"Stack allocated object not aligned to minimum required alignment");
1281
localCursor->setOffset(localCursor->getOffset() + size);
1282
localCursor = automaticIterator.getNext();
1283
}
1284
1285
ListIterator<TR::ParameterSymbol> parameterIterator(&bodySymbol->getParameterList());
1286
TR::ParameterSymbol *parmCursor = parameterIterator.getFirst();
1287
while (parmCursor != NULL)
1288
{
1289
parmCursor->setParameterOffset(parmCursor->getParameterOffset() + size);
1290
parmCursor = parameterIterator.getNext();
1291
}
1292
1293
// Save or move arguments according to the result of register assignment.
1294
// If in Full Speed Debug mode, it will not push the arguments to the stack (which was done
1295
// above) but it will complete the other operations
1296
// If not in Full Speed Debug mode, it will execute all operations in saveArguments
1297
cursor = saveArguments(cursor, fsd, false);
1298
1299
if (atlas != NULL)
1300
{
1301
TR_GCStackMap *map = atlas->getLocalMap();
1302
map->setLowestOffsetInstruction(cursor);
1303
if (!comp()->useRegisterMaps())
1304
atlas->addStackMap(map);
1305
}
1306
}
1307
1308
TR::MemoryReference *J9::Power::PrivateLinkage::getOutgoingArgumentMemRef(int32_t argSize, TR::Register *argReg, TR::InstOpCode::Mnemonic opCode, TR::PPCMemoryArgument &memArg, uint32_t length)
1309
{
1310
TR::MemoryReference *result = TR::MemoryReference::createWithDisplacement(cg(), cg()->getStackPointerRegister(), argSize, length);
1311
memArg.argRegister = argReg;
1312
memArg.argMemory = result;
1313
memArg.opCode = opCode;
1314
return(result);
1315
}
1316
1317
void J9::Power::PrivateLinkage::createEpilogue(TR::Instruction *cursor)
1318
{
1319
TR::Machine *machine = cg()->machine();
1320
const TR::PPCLinkageProperties& properties = getProperties();
1321
TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol();
1322
TR::RealRegister *stackPtr = cg()->getStackPointerRegister();
1323
TR::RealRegister *gr12 = machine->getRealRegister(TR::RealRegister::gr12);
1324
TR::RealRegister *gr0 = machine->getRealRegister(TR::RealRegister::gr0);
1325
TR::Node *currentNode = cursor->getNode();
1326
int32_t saveSize;
1327
int32_t frameSize = cg()->getFrameSizeInBytes();
1328
TR::RealRegister::RegNum savedFirst=TR::RealRegister::gr15;
1329
TR::RealRegister::RegNum regIndex;
1330
bool restoreLR = (cg()->getSnippetList().size()>1 ||
1331
(comp()->isDLT() && !cg()->getSnippetList().empty()) ||
1332
bodySymbol->isEHAware() ||
1333
cg()->canExceptByTrap() ||
1334
machine->getLinkRegisterKilled());
1335
1336
bool saveLR = restoreLR || machine->getLinkRegisterKilled();
1337
1338
1339
if (restoreLR && frameSize <= UPPER_IMMED)
1340
{
1341
cursor = generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, currentNode, gr0, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, frameSize, TR::Compiler->om.sizeofReferenceAddress()), cursor);
1342
cursor = generateSrc1Instruction(cg(), TR::InstOpCode::mtlr, currentNode, gr0, 0, cursor);
1343
}
1344
1345
if (0 && comp()->target().is64Bit())
1346
{
1347
saveSize = (cg()->getLargestOutgoingArgSize() * 2) + getOffsetToFirstParm();
1348
}
1349
else
1350
{
1351
saveSize = cg()->getLargestOutgoingArgSize() + getOffsetToFirstParm();
1352
}
1353
1354
while (savedFirst<=TR::RealRegister::LastGPR && !machine->getRealRegister(savedFirst)->getHasBeenAssignedInMethod())
1355
savedFirst=(TR::RealRegister::RegNum)((uint32_t)savedFirst+1);
1356
1357
if (savedFirst <= TR::RealRegister::LastGPR)
1358
{
1359
if (comp()->target().is64Bit() ||
1360
(TR::RealRegister::LastGPR - savedFirst <= 3))
1361
{
1362
for (regIndex=savedFirst; regIndex<=TR::RealRegister::LastGPR; regIndex=(TR::RealRegister::RegNum)((uint32_t)regIndex+1))
1363
{
1364
cursor = generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, currentNode, machine->getRealRegister(regIndex), TR::MemoryReference::createWithDisplacement(cg(), stackPtr, saveSize, TR::Compiler->om.sizeofReferenceAddress()), cursor);
1365
1366
saveSize = saveSize + TR::Compiler->om.sizeofReferenceAddress();
1367
}
1368
}
1369
else
1370
{
1371
cursor = generateTrg1MemInstruction(cg(), (savedFirst==TR::RealRegister::LastGPR)?TR::InstOpCode::lwz:TR::InstOpCode::lmw, currentNode, machine->getRealRegister(savedFirst), TR::MemoryReference::createWithDisplacement(cg(), stackPtr, saveSize, 4*(TR::RealRegister::LastGPR-savedFirst+1)), cursor);
1372
1373
saveSize += (TR::RealRegister::LastGPR - savedFirst + 1) * 4;
1374
}
1375
}
1376
1377
if (frameSize || saveLR)
1378
{
1379
saveSize = cg()->getFrameSizeInBytes() + TR::Compiler->om.sizeofReferenceAddress();
1380
if (saveSize > UPPER_IMMED)
1381
{
1382
cursor = loadConstant(cg(), currentNode, saveSize, gr12, cursor);
1383
cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::add, currentNode, stackPtr, stackPtr, gr12, cursor);
1384
}
1385
else
1386
{
1387
cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addi2, currentNode, stackPtr, stackPtr, saveSize, cursor);
1388
}
1389
1390
if (restoreLR && frameSize > UPPER_IMMED)
1391
{
1392
cursor = generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, currentNode, gr0, TR::MemoryReference::createWithDisplacement(cg(), stackPtr, -TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()), cursor);
1393
cursor = generateSrc1Instruction(cg(), TR::InstOpCode::mtlr, currentNode, gr0, 0, cursor);
1394
}
1395
}
1396
}
1397
1398
int32_t J9::Power::PrivateLinkage::buildArgs(TR::Node *callNode,
1399
TR::RegisterDependencyConditions *dependencies)
1400
{
1401
return buildPrivateLinkageArgs(callNode, dependencies, TR_Private);
1402
}
1403
1404
int32_t J9::Power::PrivateLinkage::buildPrivateLinkageArgs(TR::Node *callNode,
1405
TR::RegisterDependencyConditions *dependencies,
1406
TR_LinkageConventions linkage)
1407
{
1408
TR_ASSERT(linkage == TR_Private || linkage == TR_Helper || linkage == TR_CHelper, "Unexpected linkage convention");
1409
1410
const TR::PPCLinkageProperties& properties = getProperties();
1411
TR::PPCMemoryArgument *pushToMemory = NULL;
1412
TR::Register *tempRegister;
1413
int32_t argIndex = 0, memArgs = 0, from, to, step;
1414
int32_t argSize = -getOffsetToFirstParm(), totalSize = 0;
1415
uint32_t numIntegerArgs = 0;
1416
uint32_t numFloatArgs = 0;
1417
uint32_t firstExplicitArg = 0;
1418
TR::Node *child;
1419
void *smark;
1420
uint32_t firstArgumentChild = callNode->getFirstArgumentIndex();
1421
TR::DataType resType = callNode->getType();
1422
TR_Array<TR::Register *>& tempLongRegisters = cg()->getTransientLongRegisters();
1423
TR::MethodSymbol *callSymbol = callNode->getSymbol()->castToMethodSymbol();
1424
1425
bool isHelperCall = linkage == TR_Helper || linkage == TR_CHelper;
1426
bool rightToLeft = isHelperCall &&
1427
//we want the arguments for induceOSR to be passed from left to right as in any other non-helper call
1428
!callNode->getSymbolReference()->isOSRInductionHelper();
1429
1430
if (rightToLeft)
1431
{
1432
from = callNode->getNumChildren() - 1;
1433
to = firstArgumentChild;
1434
step = -1;
1435
}
1436
else
1437
{
1438
from = firstArgumentChild;
1439
to = callNode->getNumChildren() - 1;
1440
step = 1;
1441
}
1442
1443
if (!properties.getPreserved(TR::RealRegister::gr2))
1444
{
1445
// Helper linkage preserves all registers that are not argument registers, so we don't need to spill them.
1446
if (linkage != TR_Helper)
1447
TR::addDependency(dependencies, NULL, TR::RealRegister::gr2, TR_GPR, cg());
1448
}
1449
1450
uint32_t numIntArgRegs = properties.getNumIntArgRegs();
1451
uint32_t numFloatArgRegs = properties.getNumFloatArgRegs();
1452
TR::RealRegister::RegNum specialArgReg = TR::RealRegister::NoReg;
1453
switch (callSymbol->getMandatoryRecognizedMethod())
1454
{
1455
// Node: special long args are still only passed in one GPR
1456
case TR::java_lang_invoke_ComputedCalls_dispatchJ9Method:
1457
specialArgReg = getProperties().getJ9MethodArgumentRegister();
1458
// Other args go in memory
1459
numIntArgRegs = 0;
1460
numFloatArgRegs = 0;
1461
break;
1462
case TR::java_lang_invoke_ComputedCalls_dispatchVirtual:
1463
case TR::com_ibm_jit_JITHelpers_dispatchVirtual:
1464
specialArgReg = getProperties().getVTableIndexArgumentRegister();
1465
break;
1466
}
1467
1468
if (specialArgReg != TR::RealRegister::NoReg)
1469
{
1470
if (comp()->getOption(TR_TraceCG))
1471
{
1472
traceMsg(comp(), "Special arg %s in %s\n",
1473
comp()->getDebug()->getName(callNode->getChild(from)),
1474
comp()->getDebug()->getName(cg()->machine()->getRealRegister(specialArgReg)));
1475
}
1476
// Skip the special arg in the first loop
1477
from += step;
1478
}
1479
1480
// C helpers have an implicit first argument (the VM thread) that we have to account for
1481
if (linkage == TR_CHelper)
1482
{
1483
TR_ASSERT(numIntArgRegs > 0, "This code doesn't handle passing this implicit arg on the stack");
1484
numIntegerArgs++;
1485
totalSize += TR::Compiler->om.sizeofReferenceAddress();
1486
}
1487
1488
for (int32_t i = from; (rightToLeft && i >= to) || (!rightToLeft && i <= to); i += step)
1489
{
1490
child = callNode->getChild(i);
1491
switch (child->getDataType())
1492
{
1493
case TR::Int8:
1494
case TR::Int16:
1495
case TR::Int32:
1496
case TR::Address:
1497
if (numIntegerArgs >= numIntArgRegs)
1498
memArgs++;
1499
numIntegerArgs++;
1500
totalSize += TR::Compiler->om.sizeofReferenceAddress();
1501
break;
1502
case TR::Int64:
1503
if (comp()->target().is64Bit())
1504
{
1505
if (numIntegerArgs >= numIntArgRegs)
1506
memArgs++;
1507
numIntegerArgs++;
1508
}
1509
else
1510
{
1511
if (numIntegerArgs+1 == numIntArgRegs)
1512
memArgs++;
1513
else if (numIntegerArgs+1 > numIntArgRegs)
1514
memArgs += 2;
1515
numIntegerArgs += 2;
1516
}
1517
totalSize += 2*TR::Compiler->om.sizeofReferenceAddress();
1518
break;
1519
case TR::Float:
1520
if (numFloatArgs >= numFloatArgRegs)
1521
memArgs++;
1522
numFloatArgs++;
1523
totalSize += TR::Compiler->om.sizeofReferenceAddress();
1524
break;
1525
case TR::Double:
1526
if (numFloatArgs >= numFloatArgRegs)
1527
memArgs++;
1528
numFloatArgs++;
1529
totalSize += 2*TR::Compiler->om.sizeofReferenceAddress();
1530
break;
1531
}
1532
}
1533
1534
// From here, down, any new stack allocations will expire / die when the function returns
1535
TR::StackMemoryRegion stackMemoryRegion(*trMemory());
1536
1537
if (memArgs > 0)
1538
{
1539
pushToMemory = new (trStackMemory()) TR::PPCMemoryArgument[memArgs];
1540
}
1541
1542
if (specialArgReg)
1543
from -= step; // we do want to process special args in the following loop
1544
1545
numIntegerArgs = 0;
1546
numFloatArgs = 0;
1547
1548
// C helpers have an implicit first argument (the VM thread) that we have to account for
1549
if (linkage == TR_CHelper)
1550
{
1551
TR_ASSERT(numIntArgRegs > 0, "This code doesn't handle passing this implicit arg on the stack");
1552
TR::Register *vmThreadArgRegister = cg()->allocateRegister();
1553
generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, callNode, vmThreadArgRegister, cg()->getMethodMetaDataRegister());
1554
dependencies->addPreCondition(vmThreadArgRegister, properties.getIntegerArgumentRegister(numIntegerArgs));
1555
if (resType.getDataType() == TR::NoType)
1556
dependencies->addPostCondition(vmThreadArgRegister, properties.getIntegerArgumentRegister(numIntegerArgs));
1557
numIntegerArgs++;
1558
firstExplicitArg = 1;
1559
}
1560
1561
// Helper linkage preserves all argument registers except the return register
1562
// TODO: C helper linkage does not, this code needs to make sure argument registers are killed in post dependencies
1563
for (int32_t i = from; (rightToLeft && i >= to) || (!rightToLeft && i <= to); i += step)
1564
{
1565
TR::MemoryReference *mref = NULL;
1566
TR::Register *argRegister;
1567
child = callNode->getChild(i);
1568
bool isSpecialArg = (i == from && specialArgReg != TR::RealRegister::NoReg);
1569
switch (child->getDataType())
1570
{
1571
case TR::Int8:
1572
case TR::Int16:
1573
case TR::Int32:
1574
case TR::Address: // have to do something for GC maps here
1575
if (i == firstArgumentChild && callNode->getOpCode().isIndirect())
1576
{
1577
argRegister = pushThis(child);
1578
}
1579
else
1580
{
1581
if (child->getDataType() == TR::Address)
1582
{
1583
argRegister = pushAddressArg(child);
1584
}
1585
else
1586
{
1587
argRegister = pushIntegerWordArg(child);
1588
}
1589
}
1590
if (isSpecialArg)
1591
{
1592
if (specialArgReg == properties.getIntegerReturnRegister(0))
1593
{
1594
TR::Register *resultReg;
1595
if (resType.isAddress())
1596
resultReg = cg()->allocateCollectedReferenceRegister();
1597
else
1598
resultReg = cg()->allocateRegister();
1599
dependencies->addPreCondition(argRegister, specialArgReg);
1600
dependencies->addPostCondition(resultReg, properties.getIntegerReturnRegister(0));
1601
}
1602
else
1603
{
1604
TR::addDependency(dependencies, argRegister, specialArgReg, TR_GPR, cg());
1605
}
1606
}
1607
else
1608
{
1609
argSize += TR::Compiler->om.sizeofReferenceAddress();
1610
if (numIntegerArgs < numIntArgRegs)
1611
{
1612
if (!cg()->canClobberNodesRegister(child, 0))
1613
{
1614
if (argRegister->containsCollectedReference())
1615
tempRegister = cg()->allocateCollectedReferenceRegister();
1616
else
1617
tempRegister = cg()->allocateRegister();
1618
generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, callNode, tempRegister, argRegister);
1619
argRegister = tempRegister;
1620
}
1621
if (numIntegerArgs == firstExplicitArg &&
1622
(resType.isInt32() || resType.isInt64() || resType.isAddress()))
1623
{
1624
TR::Register *resultReg;
1625
if (resType.isAddress())
1626
resultReg = cg()->allocateCollectedReferenceRegister();
1627
else
1628
resultReg = cg()->allocateRegister();
1629
dependencies->addPreCondition(argRegister, properties.getIntegerArgumentRegister(numIntegerArgs));
1630
dependencies->addPostCondition(resultReg, TR::RealRegister::gr3);
1631
if (firstExplicitArg == 1)
1632
dependencies->addPostCondition(argRegister, properties.getIntegerArgumentRegister(numIntegerArgs));
1633
}
1634
else if (comp()->target().is32Bit() && numIntegerArgs == (firstExplicitArg + 1) && resType.isInt64())
1635
{
1636
TR::Register *resultReg = cg()->allocateRegister();
1637
dependencies->addPreCondition(argRegister, properties.getIntegerArgumentRegister(numIntegerArgs));
1638
dependencies->addPostCondition(resultReg, TR::RealRegister::gr4);
1639
if (firstExplicitArg == 1)
1640
dependencies->addPostCondition(argRegister, properties.getIntegerArgumentRegister(numIntegerArgs));
1641
}
1642
else
1643
{
1644
TR::addDependency(dependencies, argRegister, properties.getIntegerArgumentRegister(numIntegerArgs), TR_GPR, cg());
1645
}
1646
}
1647
else // numIntegerArgs >= numIntArgRegs
1648
{
1649
if (child->getDataType() == TR::Address)
1650
mref = getOutgoingArgumentMemRef(totalSize-argSize, argRegister,TR::InstOpCode::Op_st, pushToMemory[argIndex++], TR::Compiler->om.sizeofReferenceAddress());
1651
else
1652
mref = getOutgoingArgumentMemRef(totalSize-argSize, argRegister, TR::InstOpCode::stw, pushToMemory[argIndex++], 4);
1653
}
1654
numIntegerArgs++;
1655
}
1656
break;
1657
case TR::Int64:
1658
argRegister = pushLongArg(child);
1659
if (isSpecialArg)
1660
{
1661
// Note: special arg regs use only one reg even on 32-bit platforms.
1662
// If the special arg is of type TR::Int64, that only means we don't
1663
// care about the top 32 bits.
1664
TR::Register *specialArgRegister = argRegister->getRegisterPair()? argRegister->getLowOrder() : argRegister;
1665
if (specialArgReg == properties.getIntegerReturnRegister(0))
1666
{
1667
TR::Register *resultReg;
1668
if (resType.isAddress())
1669
resultReg = cg()->allocateCollectedReferenceRegister();
1670
else
1671
resultReg = cg()->allocateRegister();
1672
dependencies->addPreCondition(specialArgRegister, specialArgReg);
1673
dependencies->addPostCondition(resultReg, properties.getIntegerReturnRegister(0));
1674
}
1675
else
1676
{
1677
TR::addDependency(dependencies, specialArgRegister, specialArgReg, TR_GPR, cg());
1678
}
1679
}
1680
else
1681
{
1682
argSize += 2*TR::Compiler->om.sizeofReferenceAddress();
1683
if (numIntegerArgs < numIntArgRegs)
1684
{
1685
if (!cg()->canClobberNodesRegister(child, 0))
1686
{
1687
if (comp()->target().is64Bit())
1688
{
1689
if (argRegister->containsCollectedReference())
1690
tempRegister = cg()->allocateCollectedReferenceRegister();
1691
else
1692
tempRegister = cg()->allocateRegister();
1693
generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, callNode, tempRegister, argRegister);
1694
argRegister = tempRegister;
1695
}
1696
else
1697
{
1698
tempRegister = cg()->allocateRegister();
1699
generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, callNode, tempRegister, argRegister->getRegisterPair()->getHighOrder());
1700
argRegister = cg()->allocateRegisterPair(argRegister->getRegisterPair()->getLowOrder(), tempRegister);
1701
tempLongRegisters.add(argRegister);
1702
}
1703
}
1704
if (numIntegerArgs == firstExplicitArg && (resType.isInt32() || resType.isInt64() || resType.isAddress()))
1705
{
1706
TR::Register *resultReg;
1707
if (resType.isAddress())
1708
resultReg = cg()->allocateCollectedReferenceRegister();
1709
else
1710
resultReg = cg()->allocateRegister();
1711
if (comp()->target().is64Bit())
1712
dependencies->addPreCondition(argRegister, properties.getIntegerArgumentRegister(numIntegerArgs));
1713
else
1714
dependencies->addPreCondition(argRegister->getRegisterPair()->getHighOrder(), properties.getIntegerArgumentRegister(numIntegerArgs));
1715
dependencies->addPostCondition(resultReg, TR::RealRegister::gr3);
1716
if (firstExplicitArg == 1)
1717
dependencies->addPostCondition(argRegister, properties.getIntegerArgumentRegister(numIntegerArgs));
1718
}
1719
else if (comp()->target().is32Bit() && numIntegerArgs == (firstExplicitArg + 1) && resType.isInt64())
1720
{
1721
TR::Register *resultReg = cg()->allocateRegister();
1722
dependencies->addPreCondition(argRegister->getRegisterPair()->getHighOrder(), properties.getIntegerArgumentRegister(numIntegerArgs));
1723
dependencies->addPostCondition(resultReg, TR::RealRegister::gr4);
1724
if (firstExplicitArg == 1)
1725
dependencies->addPostCondition(argRegister, properties.getIntegerArgumentRegister(numIntegerArgs));
1726
}
1727
else
1728
{
1729
if (comp()->target().is64Bit())
1730
TR::addDependency(dependencies, argRegister, properties.getIntegerArgumentRegister(numIntegerArgs), TR_GPR, cg());
1731
else
1732
TR::addDependency(dependencies, argRegister->getRegisterPair()->getHighOrder(), properties.getIntegerArgumentRegister(numIntegerArgs), TR_GPR, cg());
1733
}
1734
if (comp()->target().is32Bit())
1735
{
1736
if (numIntegerArgs+1 < numIntArgRegs)
1737
{
1738
if (!cg()->canClobberNodesRegister(child, 0))
1739
{
1740
TR::Register *over_lowReg = argRegister->getRegisterPair()->getLowOrder();
1741
tempRegister = cg()->allocateRegister();
1742
generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, callNode, tempRegister, over_lowReg);
1743
argRegister->getRegisterPair()->setLowOrder(tempRegister, cg());
1744
}
1745
if (numIntegerArgs == firstExplicitArg && resType.isInt64())
1746
{
1747
TR::Register *resultReg = cg()->allocateRegister();
1748
dependencies->addPreCondition(argRegister->getRegisterPair()->getLowOrder(), properties.getIntegerArgumentRegister(numIntegerArgs + 1));
1749
dependencies->addPostCondition(resultReg, TR::RealRegister::gr4);
1750
if (firstExplicitArg == 1)
1751
dependencies->addPostCondition(argRegister, properties.getIntegerArgumentRegister(numIntegerArgs + 1));
1752
}
1753
else
1754
TR::addDependency(dependencies, argRegister->getRegisterPair()->getLowOrder(), properties.getIntegerArgumentRegister(numIntegerArgs+1), TR_GPR, cg());
1755
}
1756
else // numIntegerArgs+1 == numIntArgRegs
1757
mref = getOutgoingArgumentMemRef(totalSize-argSize+4, argRegister->getRegisterPair()->getLowOrder(), TR::InstOpCode::stw, pushToMemory[argIndex++], 4);
1758
numIntegerArgs++;
1759
}
1760
}
1761
else // numIntegerArgs >= numIntArgRegs
1762
{
1763
if (comp()->target().is64Bit())
1764
mref = getOutgoingArgumentMemRef(totalSize-argSize, argRegister, TR::InstOpCode::std, pushToMemory[argIndex++], 8);
1765
else
1766
{
1767
mref = getOutgoingArgumentMemRef(totalSize-argSize, argRegister->getRegisterPair()->getHighOrder(), TR::InstOpCode::stw, pushToMemory[argIndex++], 4);
1768
mref = getOutgoingArgumentMemRef(totalSize-argSize+4, argRegister->getRegisterPair()->getLowOrder(), TR::InstOpCode::stw, pushToMemory[argIndex++], 4);
1769
numIntegerArgs++;
1770
}
1771
}
1772
numIntegerArgs++;
1773
}
1774
break;
1775
case TR::Float:
1776
argSize += TR::Compiler->om.sizeofReferenceAddress();
1777
argRegister = pushFloatArg(child);
1778
if (numFloatArgs < numFloatArgRegs)
1779
{
1780
if (!cg()->canClobberNodesRegister(child, 0))
1781
{
1782
tempRegister = cg()->allocateRegister(TR_FPR);
1783
generateTrg1Src1Instruction(cg(), TR::InstOpCode::fmr, callNode, tempRegister, argRegister);
1784
argRegister = tempRegister;
1785
}
1786
if (numFloatArgs == 0 && resType.isFloatingPoint())
1787
{
1788
TR::Register *resultReg;
1789
if (resType.getDataType() == TR::Float)
1790
resultReg = cg()->allocateSinglePrecisionRegister();
1791
else
1792
resultReg = cg()->allocateRegister(TR_FPR);
1793
dependencies->addPreCondition(argRegister, TR::RealRegister::fp0);
1794
dependencies->addPostCondition(resultReg, TR::RealRegister::fp0);
1795
}
1796
else
1797
TR::addDependency(dependencies, argRegister, properties.getFloatArgumentRegister(numFloatArgs), TR_FPR, cg());
1798
}
1799
else // numFloatArgs >= numFloatArgRegs
1800
{
1801
mref = getOutgoingArgumentMemRef(totalSize-argSize, argRegister, TR::InstOpCode::stfs, pushToMemory[argIndex++], 4);
1802
}
1803
numFloatArgs++;
1804
break;
1805
case TR::Double:
1806
argSize += 2*TR::Compiler->om.sizeofReferenceAddress();
1807
argRegister = pushDoubleArg(child);
1808
if (numFloatArgs < numFloatArgRegs)
1809
{
1810
if (!cg()->canClobberNodesRegister(child, 0))
1811
{
1812
tempRegister = cg()->allocateRegister(TR_FPR);
1813
generateTrg1Src1Instruction(cg(), TR::InstOpCode::fmr, callNode, tempRegister, argRegister);
1814
argRegister = tempRegister;
1815
}
1816
if (numFloatArgs == 0 && resType.isFloatingPoint())
1817
{
1818
TR::Register *resultReg;
1819
if (resType.getDataType() == TR::Float)
1820
resultReg = cg()->allocateSinglePrecisionRegister();
1821
else
1822
resultReg = cg()->allocateRegister(TR_FPR);
1823
dependencies->addPreCondition(argRegister, TR::RealRegister::fp0);
1824
dependencies->addPostCondition(resultReg, TR::RealRegister::fp0);
1825
}
1826
else
1827
TR::addDependency(dependencies, argRegister, properties.getFloatArgumentRegister(numFloatArgs), TR_FPR, cg());
1828
}
1829
else // numFloatArgs >= numFloatArgRegs
1830
{
1831
mref = getOutgoingArgumentMemRef(totalSize-argSize, argRegister, TR::InstOpCode::stfd, pushToMemory[argIndex++], 8);
1832
}
1833
numFloatArgs++;
1834
break;
1835
}
1836
}
1837
1838
if (!dependencies->searchPreConditionRegister(TR::RealRegister::gr11))
1839
TR::addDependency(dependencies, NULL, TR::RealRegister::gr11, TR_GPR, cg());
1840
if (!dependencies->searchPreConditionRegister(TR::RealRegister::gr12))
1841
TR::addDependency(dependencies, NULL, TR::RealRegister::gr12, TR_GPR, cg());
1842
1843
for (int32_t i = TR::RealRegister::FirstGPR; i <= TR::RealRegister::LastGPR; ++i)
1844
{
1845
TR::RealRegister::RegNum realReg = (TR::RealRegister::RegNum)i;
1846
if (properties.getPreserved(realReg))
1847
continue;
1848
if (realReg == specialArgReg)
1849
continue; // already added deps above. No need to add them here.
1850
if (callSymbol->isComputed() && i == getProperties().getComputedCallTargetRegister())
1851
continue; // will be handled elsewhere
1852
if (!dependencies->searchPreConditionRegister(realReg))
1853
{
1854
if (realReg == properties.getIntegerArgumentRegister(0) && callNode->getDataType() == TR::Address)
1855
{
1856
dependencies->addPreCondition(cg()->allocateRegister(), TR::RealRegister::gr3);
1857
dependencies->addPostCondition(cg()->allocateCollectedReferenceRegister(), TR::RealRegister::gr3);
1858
}
1859
else
1860
{
1861
// Helper linkage preserves all registers that are not argument registers, so we don't need to spill them.
1862
if (linkage != TR_Helper)
1863
TR::addDependency(dependencies, NULL, realReg, TR_GPR, cg());
1864
}
1865
}
1866
}
1867
1868
TR_LiveRegisters *lr = cg()->getLiveRegisters(TR_FPR);
1869
bool liveFPR, liveVSX, liveVMX;
1870
1871
liveFPR = (!lr || lr->getNumberOfLiveRegisters() > 0);
1872
1873
lr = cg()->getLiveRegisters(TR_VSX_SCALAR);
1874
liveVSX = (!lr || lr->getNumberOfLiveRegisters() > 0);
1875
lr = cg()->getLiveRegisters(TR_VSX_VECTOR);
1876
liveVSX |= (!lr || lr->getNumberOfLiveRegisters() > 0);
1877
1878
lr = cg()->getLiveRegisters(TR_VRF);
1879
liveVMX = (!lr || lr->getNumberOfLiveRegisters() > 0);
1880
1881
if (liveVSX || liveFPR)
1882
{
1883
while (numFloatArgs < 8)
1884
{
1885
TR::addDependency(dependencies, NULL, (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fp0+numFloatArgs), TR_FPR, cg());
1886
numFloatArgs++;
1887
}
1888
1889
int32_t theLastOne = liveVSX ? TR::RealRegister::LastVSR : TR::RealRegister::LastFPR;
1890
for (int32_t i = TR::RealRegister::fp8; i <= theLastOne; i++)
1891
if (!properties.getPreserved((TR::RealRegister::RegNum)i))
1892
{
1893
TR::addDependency(dependencies, NULL, (TR::RealRegister::RegNum)i, (i>TR::RealRegister::LastFPR)?TR_VSX_SCALAR:TR_FPR, cg());
1894
}
1895
}
1896
else if (callNode->getType().isFloatingPoint())
1897
{
1898
//add return floating-point register dependency
1899
TR::addDependency(dependencies, NULL, (TR::RealRegister::RegNum)getProperties().getFloatReturnRegister(), TR_FPR, cg());
1900
}
1901
1902
if (!liveVSX && liveVMX)
1903
{
1904
for (int32_t i = TR::RealRegister::vr0; i <= TR::RealRegister::vr31; i++)
1905
if (!properties.getPreserved((TR::RealRegister::RegNum)i))
1906
TR::addDependency(dependencies, NULL, (TR::RealRegister::RegNum)i, TR_VSX_SCALAR, cg());
1907
}
1908
1909
1910
1911
/*
1912
PPC ABI --
1913
AIX 32-bit BE & AIX 64-bit BE & Linux 64-bit BE:
1914
These follow aix-style linkage.
1915
There is a TOC-base register (gr2) that needs to be loaded from function descriptor of that function that is called.
1916
If the callee function is in libj9jitxx.so module, (as in the case of CHelper functions are) then the module's TOC-base can be found in the J9VMThread jitTOC field.
1917
The TOC can be loaded from the jitTOC field of J9VMThread (pointed to by metaDataRegister).
1918
1919
Linux 64-bit LE: There exists a TOC (gr2), but there is no such function descriptor.
1920
The TOC-base set-up is defined by ABI to go through a function's global-entry (relocation).
1921
The global-entry address will be set up in gr12.
1922
1923
Registers r12, and r2 are always added to the dependency in the situations that they're used.
1924
R12 is added at all times, and is an unreserved register across all platforms.
1925
R2 is added to the dependency only if we're not dealing with a linux 32 bit platform, where it's system reserved.
1926
Ultimately, we don't need an assert or NULL check when searching for these registers within the dependency.
1927
*/
1928
if(linkage == TR_CHelper)
1929
{
1930
if(comp()->target().isLinux() && comp()->target().is64Bit() && comp()->target().cpu.isLittleEndian())
1931
{
1932
if (!comp()->getOption(TR_DisableTOC))
1933
{
1934
int32_t helperOffset = (callNode->getSymbolReference()->getReferenceNumber() - 1)*sizeof(intptr_t);
1935
generateTrg1MemInstruction(cg(), TR::InstOpCode::Op_load, callNode, dependencies->searchPreConditionRegister(TR::RealRegister::gr12),
1936
TR::MemoryReference::createWithDisplacement(cg(), cg()->getTOCBaseRegister(), helperOffset, TR::Compiler->om.sizeofReferenceAddress()));
1937
}
1938
else
1939
{
1940
loadAddressConstant(cg(), callNode, (int64_t)runtimeHelperValue((TR_RuntimeHelper)callNode->getSymbolReference()->getReferenceNumber()),
1941
dependencies->searchPreConditionRegister(TR::RealRegister::gr12), NULL, false, TR_AbsoluteHelperAddress);
1942
}
1943
1944
}
1945
else if (comp()->target().isAIX() || (comp()->target().isLinux() && comp()->target().is64Bit()))
1946
{
1947
generateTrg1MemInstruction(cg(), TR::InstOpCode::Op_load, callNode, dependencies->searchPreConditionRegister(TR::RealRegister::gr2),
1948
TR::MemoryReference::createWithDisplacement(cg(), cg()->getMethodMetaDataRegister(), offsetof(J9VMThread, jitTOC), TR::Compiler->om.sizeofReferenceAddress()));
1949
}
1950
}
1951
1952
1953
// This is a performance hack. CCRs are rarely live across calls,
1954
// particularly helper calls, but because we create scratch virtual
1955
// regs and re-use them during evaluation they appear live.
1956
// This is often made worse by OOL code, the SRM, internal control flow.
1957
// The cost of saving/restoring CCRs in particular is very high and
1958
// fixing this problem is otherwise is not easy, hence this hack.
1959
// If you need to disable this hack, use this env var.
1960
static bool forcePreserveCCRs = feGetEnv("TR_ppcForcePreserveCCRsOnCalls") != NULL;
1961
if (linkage == TR_Private || forcePreserveCCRs)
1962
{
1963
lr = cg()->getLiveRegisters(TR_CCR);
1964
if(!lr || lr->getNumberOfLiveRegisters() > 0 )
1965
{
1966
for (int32_t i = TR::RealRegister::FirstCCR; i <= TR::RealRegister::LastCCR; i++)
1967
if (!properties.getPreserved((TR::RealRegister::RegNum)i))
1968
{
1969
TR::addDependency(dependencies, NULL, (TR::RealRegister::RegNum)i, TR_CCR, cg());
1970
}
1971
}
1972
else
1973
{
1974
//add the FirstCCR if there is no live CCR available,
1975
//because on buildVirtualDispatch(), it gets the CCR dependency from search
1976
if (!properties.getPreserved(TR::RealRegister::FirstCCR))
1977
{
1978
TR::addDependency(dependencies, NULL, TR::RealRegister::FirstCCR, TR_CCR, cg());
1979
}
1980
}
1981
}
1982
else if (comp()->getOption(TR_TraceCG))
1983
traceMsg(comp(), "Omitting CCR save/restore for helper calls\n");
1984
1985
if (memArgs > 0)
1986
{
1987
for (argIndex = 0; argIndex < memArgs; argIndex++)
1988
{
1989
TR::Register *aReg = pushToMemory[argIndex].argRegister;
1990
generateMemSrc1Instruction(cg(), pushToMemory[argIndex].opCode, callNode, pushToMemory[argIndex].argMemory, aReg);
1991
cg()->stopUsingRegister(aReg);
1992
}
1993
}
1994
1995
return totalSize;
1996
}
1997
1998
static bool getProfiledCallSiteInfo(TR::CodeGenerator *cg, TR::Node *callNode, uint32_t maxStaticPICs, TR_ScratchList<J9::PPCPICItem> &values)
1999
{
2000
TR::Compilation *comp = cg->comp();
2001
TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());
2002
if (comp->compileRelocatableCode())
2003
return false;
2004
2005
TR::SymbolReference *methodSymRef = callNode->getSymbolReference();
2006
TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();
2007
2008
if (!methodSymbol->isVirtual() && !methodSymbol->isInterface())
2009
return false;
2010
2011
TR_AddressInfo *info = static_cast<TR_AddressInfo*>(TR_ValueProfileInfoManager::getProfiledValueInfo(callNode, comp, AddressInfo));
2012
if (!info)
2013
return false;
2014
2015
uint32_t totalFreq = info->getTotalFrequency();
2016
if (totalFreq == 0 || info->getTopProbability() < MIN_PROFILED_CALL_FREQUENCY)
2017
return false;
2018
2019
TR_ScratchList<TR_ExtraAddressInfo> allValues(comp->trMemory());
2020
info->getSortedList(comp, &allValues);
2021
2022
TR_ResolvedMethod *owningMethod = methodSymRef->getOwningMethod(comp);
2023
TR_OpaqueClassBlock *callSiteMethodClass;
2024
2025
if (methodSymbol->isVirtual())
2026
callSiteMethodClass = methodSymRef->getSymbol()->getResolvedMethodSymbol()->getResolvedMethod()->classOfMethod();
2027
2028
ListIterator<TR_ExtraAddressInfo> valuesIt(&allValues);
2029
2030
uint32_t numStaticPics = 0;
2031
TR_ExtraAddressInfo *profiledInfo;
2032
for (profiledInfo = valuesIt.getFirst(); numStaticPics < maxStaticPICs && profiledInfo != NULL; profiledInfo = valuesIt.getNext())
2033
{
2034
float freq = (float)profiledInfo->_frequency / totalFreq;
2035
if (freq < MIN_PROFILED_CALL_FREQUENCY)
2036
break;
2037
2038
TR_OpaqueClassBlock *clazz = (TR_OpaqueClassBlock *)profiledInfo->_value;
2039
if (comp->getPersistentInfo()->isObsoleteClass(clazz, fej9))
2040
continue;
2041
2042
TR_ResolvedMethod *method;
2043
2044
if (methodSymbol->isVirtual())
2045
{
2046
TR_ASSERT(callSiteMethodClass, "Expecting valid callSiteMethodClass for virtual call");
2047
if (!cg->isProfiledClassAndCallSiteCompatible(clazz, callSiteMethodClass))
2048
continue;
2049
2050
method = owningMethod->getResolvedVirtualMethod(comp, clazz, methodSymRef->getOffset());
2051
}
2052
else
2053
{
2054
TR_ASSERT(methodSymbol->isInterface(), "Expecting virtual or interface method");
2055
method = owningMethod->getResolvedInterfaceMethod(comp, clazz, methodSymRef->getCPIndex());
2056
}
2057
2058
if (!method || method->isInterpreted())
2059
continue;
2060
2061
values.add(new (comp->trStackMemory()) J9::PPCPICItem(clazz, method, freq));
2062
++numStaticPics;
2063
}
2064
2065
return numStaticPics > 0;
2066
}
2067
2068
static TR::Instruction* buildStaticPICCall(TR::CodeGenerator *cg, TR::Node *callNode, uintptr_t profiledClass, TR_ResolvedMethod *profiledMethod,
2069
TR::Register *vftReg, TR::Register *tempReg, TR::Register *condReg, TR::LabelSymbol *missLabel,
2070
uint32_t regMapForGC)
2071
{
2072
TR::Compilation *comp = cg->comp();
2073
TR::SymbolReference *methodSymRef = callNode->getSymbolReference();
2074
TR::SymbolReference *profiledMethodSymRef = comp->getSymRefTab()->findOrCreateMethodSymbol(methodSymRef->getOwningMethodIndex(),
2075
-1,
2076
profiledMethod,
2077
TR::MethodSymbol::Virtual);
2078
2079
TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());
2080
loadAddressConstant(cg, comp->compileRelocatableCode(), callNode, profiledClass, tempReg, NULL, fej9->isUnloadAssumptionRequired((TR_OpaqueClassBlock *)profiledClass, comp->getCurrentMethod()));
2081
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, callNode, condReg, vftReg, tempReg);
2082
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, callNode, missLabel, condReg);
2083
TR::Instruction *gcPoint = generateDepImmSymInstruction(cg, TR::InstOpCode::bl, callNode, (uintptr_t)profiledMethod->startAddressForJittedMethod(),
2084
new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0,0, cg->trMemory()), profiledMethodSymRef);
2085
gcPoint->PPCNeedsGCMap(regMapForGC);
2086
fej9->reserveTrampolineIfNecessary(comp, profiledMethodSymRef, false);
2087
return gcPoint;
2088
}
2089
2090
static void buildVirtualCall(TR::CodeGenerator *cg, TR::Node *callNode, TR::Register *vftReg, TR::Register *gr12, uint32_t regMapForGC)
2091
{
2092
int32_t offset = callNode->getSymbolReference()->getOffset();
2093
TR::Compilation* comp = cg->comp();
2094
2095
// jitrt.dev/ppc/Recompilation.s is dependent on the code sequence
2096
// generated from here to the bctrl below!!
2097
// DO NOT MODIFY without also changing Recompilation.s!!
2098
if (offset < LOWER_IMMED || offset > UPPER_IMMED)
2099
{
2100
TR_ASSERT_FATAL_WITH_NODE(callNode, 0x00008000 != HI_VALUE(offset), "offset (0x%x) is unexpectedly high. Can not encode upper 16 bits into an addis instruction.", offset);
2101
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addis, callNode, gr12, vftReg, HI_VALUE(offset));
2102
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr12, TR::MemoryReference::createWithDisplacement(cg, gr12, LO_VALUE(offset), TR::Compiler->om.sizeofReferenceAddress()));
2103
}
2104
else
2105
{
2106
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr12, TR::MemoryReference::createWithDisplacement(cg, vftReg, offset, TR::Compiler->om.sizeofReferenceAddress()));
2107
}
2108
2109
generateSrc1Instruction(cg, TR::InstOpCode::mtctr, callNode, gr12);
2110
TR::Instruction *gcPoint = generateInstruction(cg, TR::InstOpCode::bctrl, callNode);
2111
gcPoint->PPCNeedsGCMap(regMapForGC);
2112
}
2113
2114
static void buildInterfaceCall(TR::CodeGenerator *cg, TR::Node *callNode, TR::Register *vftReg, TR::Register *gr0, TR::Register *gr11, TR::Register *gr12, TR::Register *cr0, TR::PPCInterfaceCallSnippet *ifcSnippet, uint32_t regMapForGC)
2115
{
2116
TR::Compilation *comp = cg->comp();
2117
TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());
2118
2119
// jitrt.dev/ppc/Recompilation.s is dependent on the code sequence
2120
// generated from here to the bctrl below!!
2121
// DO NOT MODIFY without also changing Recompilation.s!!
2122
if (comp->target().is64Bit())
2123
{
2124
if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10))
2125
{
2126
// Expecting the 64bit IPIC snippet shape
2127
generateTrg1MemInstruction(cg, TR::InstOpCode::paddi, callNode, gr12, TR::MemoryReference::createWithLabel(cg, ifcSnippet->getSnippetLabel(), 12+4*TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()));
2128
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr11, TR::MemoryReference::createWithDisplacement(cg, gr12, 0, TR::Compiler->om.sizeofReferenceAddress()));
2129
}
2130
else
2131
{
2132
int32_t beginIndex = TR_PPCTableOfConstants::allocateChunk(1, cg);
2133
2134
if (beginIndex != PTOC_FULL_INDEX)
2135
{
2136
beginIndex *= TR::Compiler->om.sizeofReferenceAddress();
2137
if (beginIndex < LOWER_IMMED || beginIndex > UPPER_IMMED)
2138
{
2139
TR_ASSERT_FATAL_WITH_NODE(callNode, 0x00008000 != HI_VALUE(beginIndex), "TOC offset (0x%x) is unexpectedly high. Can not encode upper 16 bits into an addis instruction.", beginIndex);
2140
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addis, callNode, gr12, cg->getTOCBaseRegister(), HI_VALUE(beginIndex));
2141
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr12, TR::MemoryReference::createWithDisplacement(cg, gr12, LO_VALUE(beginIndex), TR::Compiler->om.sizeofReferenceAddress()));
2142
}
2143
else
2144
{
2145
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr12, TR::MemoryReference::createWithDisplacement(cg, cg->getTOCBaseRegister(), beginIndex, TR::Compiler->om.sizeofReferenceAddress()));
2146
}
2147
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr11, TR::MemoryReference::createWithDisplacement(cg, gr12, 0, TR::Compiler->om.sizeofReferenceAddress()));
2148
}
2149
else
2150
{
2151
TR::Instruction *q[4];
2152
fixedSeqMemAccess(cg, callNode, 0, q, gr11, gr12,TR::InstOpCode::Op_loadu, TR::Compiler->om.sizeofReferenceAddress(), NULL, gr11);
2153
ifcSnippet->setLowerInstruction(q[3]);
2154
ifcSnippet->setUpperInstruction(q[0]);
2155
}
2156
ifcSnippet->setTOCOffset(beginIndex);
2157
}
2158
}
2159
else
2160
{
2161
ifcSnippet->setUpperInstruction(generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, callNode, gr12, 0));
2162
ifcSnippet->setLowerInstruction(generateTrg1MemInstruction(cg, TR::InstOpCode::lwzu, callNode, gr11, TR::MemoryReference::createWithDisplacement(cg, gr12, 0, 4)));
2163
}
2164
TR::LabelSymbol *hitLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
2165
TR::LabelSymbol *snippetLabel = ifcSnippet->getSnippetLabel();
2166
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, callNode, cr0, vftReg, gr11);
2167
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, callNode, hitLabel, cr0);
2168
2169
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_loadu, callNode, gr11, TR::MemoryReference::createWithDisplacement(cg, gr12, 2 * TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()));
2170
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, callNode, cr0, vftReg, gr11);
2171
2172
#ifdef INLINE_LASTITABLE_CHECK
2173
// Doing this check inline doesn't perform too well because it prevents the PIC cache slots from being populated with the best candidates.
2174
// This check is done in the _interfaceSlotsUnavailable helper instead.
2175
TR::LabelSymbol *callLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
2176
TR_SymbolReference *methodSymRef = callNode->getSymbolReference();
2177
TR_ResolvedMethod *owningMethod = methodSymRef->getOwningMethod(comp);
2178
TR_OpaqueClassBlock *interfaceClassOfMethod;
2179
uintptr_t itableIndex;
2180
2181
interfaceClassOfMethod = owningMethod->getResolvedInterfaceMethod(methodSymRef->getCPIndex(), &itableIndex);
2182
2183
TR_ASSERT(fej9->getITableEntryJitVTableOffset() <= UPPER_IMMED &&
2184
fej9->getITableEntryJitVTableOffset() >= LOWER_IMMED, "ITable offset for JIT is too large, prevents lastITable dispatch from being generated");
2185
2186
if (!comp->getOption(TR_DisableLastITableCache) && interfaceClassOfMethod &&
2187
// Only do this if this offset can be loaded in a single instruction because this code may need to be
2188
// patched at runtime and we don't want to deal with too many variations
2189
fej9->getITableEntryJitVTableOffset() <= UPPER_IMMED &&
2190
fej9->getITableEntryJitVTableOffset() >= LOWER_IMMED)
2191
{
2192
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, callNode, hitLabel, cr0);
2193
2194
// Check if the lastITable belongs to the interface class we're using at this call site
2195
//
2196
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr11,
2197
TR::MemoryReference::createWithDisplacement(cg, vftReg, fej9->getOffsetOfLastITableFromClassField(), TR::Compiler->om.sizeofReferenceAddress()));
2198
// Load the interface class from the snippet rather than materializing it, again because we want to do this in a single instruction
2199
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr12,
2200
TR::MemoryReference::createWithDisplacement(cg, gr12, -4 * TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()));
2201
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr0,
2202
TR::MemoryReference::createWithDisplacement(cg, gr11, fej9->getOffsetOfInterfaceClassFromITableField(), TR::Compiler->om.sizeofReferenceAddress()));
2203
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, callNode, cr0, gr0, gr12);
2204
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, callNode, snippetLabel, cr0);
2205
2206
// lastITable belongs to the interface class we're using at this call site
2207
// Use it to look up the VFT offset and use that to make a virtual call
2208
//
2209
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr12,
2210
TR::MemoryReference::createWithDisplacement(cg, gr11, fej9->convertITableIndexToOffset(itableIndex), TR::Compiler->om.sizeofReferenceAddress()));
2211
loadConstant(cg, callNode, fej9->getITableEntryJitVTableOffset(), gr11);
2212
generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, callNode, gr12, gr12, gr11);
2213
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr11,
2214
TR::MemoryReference::createWithIndexReg(cg, vftReg, gr12, TR::Compiler->om.sizeofReferenceAddress()));
2215
generateLabelInstruction(cg, TR::InstOpCode::b, callNode, callLabel);
2216
}
2217
else
2218
#endif /* INLINE_LASTITABLE_CHECK */
2219
{
2220
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, callNode, snippetLabel, cr0);
2221
}
2222
generateLabelInstruction(cg, TR::InstOpCode::label, callNode, hitLabel);
2223
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, callNode, gr11, TR::MemoryReference::createWithDisplacement(cg, gr12, TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()));
2224
#ifdef INLINE_LASTITABLE_CHECK
2225
generateLabelInstruction(cg, TR::InstOpCode::label, callNode, callLabel);
2226
#endif /* INLINE_LASTITABLE_CHECK */
2227
generateSrc1Instruction(cg, TR::InstOpCode::mtctr, callNode, gr11);
2228
TR::Instruction *gcPoint = generateInstruction(cg, TR::InstOpCode::bctrl, callNode);
2229
gcPoint->PPCNeedsGCMap(regMapForGC);
2230
ifcSnippet->gcMap().setGCRegisterMask(regMapForGC);
2231
}
2232
2233
static TR::Register* evaluateUpToVftChild(TR::Node *callNode, TR::CodeGenerator *cg)
2234
{
2235
TR::Register *vftReg;
2236
uint32_t firstArgumentChild = callNode->getFirstArgumentIndex();
2237
for (uint32_t i = 0; i < firstArgumentChild; i++)
2238
{
2239
TR::Node *child = callNode->getChild(i);
2240
vftReg = cg->evaluate(child);
2241
cg->decReferenceCount(child);
2242
}
2243
return vftReg;
2244
}
2245
2246
void J9::Power::PrivateLinkage::buildVirtualDispatch(TR::Node *callNode,
2247
TR::RegisterDependencyConditions *dependencies,
2248
uint32_t sizeOfArguments)
2249
{
2250
TR::Register *cr0 = dependencies->searchPreConditionRegister(TR::RealRegister::cr0);
2251
TR::Register *gr0 = dependencies->searchPreConditionRegister(TR::RealRegister::gr0);
2252
TR::Register *gr11 = dependencies->searchPreConditionRegister(TR::RealRegister::gr11);
2253
TR::Register *gr12 = dependencies->searchPreConditionRegister(TR::RealRegister::gr12);
2254
TR::SymbolReference *methodSymRef = callNode->getSymbolReference();
2255
TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();
2256
TR::LabelSymbol *doneLabel = generateLabelSymbol(cg());
2257
uint32_t regMapForGC = getProperties().getPreservedRegisterMapForGC();
2258
void *thunk = NULL;
2259
2260
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp()->fe());
2261
2262
// Computed calls
2263
//
2264
if (methodSymbol->isComputed())
2265
{
2266
TR::Register *vftReg = evaluateUpToVftChild(callNode, cg());
2267
// On 32-bit, we can just ignore the top 32 bits of the 64-bit target address
2268
if (vftReg->getRegisterPair())
2269
vftReg = vftReg->getLowOrder();
2270
TR::addDependency(dependencies, vftReg, getProperties().getComputedCallTargetRegister(), TR_GPR, cg());
2271
2272
switch (methodSymbol->getMandatoryRecognizedMethod())
2273
{
2274
case TR::java_lang_invoke_ComputedCalls_dispatchVirtual:
2275
case TR::com_ibm_jit_JITHelpers_dispatchVirtual:
2276
{
2277
// Need a j2i thunk for the method that will ultimately be dispatched by this handle call
2278
char *j2iSignature = fej9->getJ2IThunkSignatureForDispatchVirtual(methodSymbol->getMethod()->signatureChars(), methodSymbol->getMethod()->signatureLength(), comp());
2279
int32_t signatureLen = strlen(j2iSignature);
2280
thunk = fej9->getJ2IThunk(j2iSignature, signatureLen, comp());
2281
if (!thunk)
2282
{
2283
thunk = fej9->setJ2IThunk(j2iSignature, signatureLen,
2284
TR::PPCCallSnippet::generateVIThunk(fej9->getEquivalentVirtualCallNodeForDispatchVirtual(callNode, comp()), sizeOfArguments, cg()), comp());
2285
}
2286
}
2287
default:
2288
if (fej9->needsInvokeExactJ2IThunk(callNode, comp()))
2289
{
2290
TR_J2IThunk *thunk = TR::PPCCallSnippet::generateInvokeExactJ2IThunk(callNode, sizeOfArguments, cg(), methodSymbol->getMethod()->signatureChars());
2291
fej9->setInvokeExactJ2IThunk(thunk, comp());
2292
}
2293
break;
2294
}
2295
2296
TR::Register *targetAddress = vftReg;
2297
generateSrc1Instruction(cg(), TR::InstOpCode::mtctr, callNode, targetAddress);
2298
TR::Instruction *gcPoint = generateInstruction(cg(), TR::InstOpCode::bctrl, callNode);
2299
generateDepLabelInstruction(cg(), TR::InstOpCode::label, callNode, doneLabel, dependencies);
2300
2301
gcPoint->PPCNeedsGCMap(regMapForGC);
2302
return;
2303
}
2304
2305
// Virtual and interface calls
2306
//
2307
TR_ASSERT(methodSymbol->isVirtual() || methodSymbol->isInterface(), "Unexpected method type");
2308
2309
thunk = fej9->getJ2IThunk(methodSymbol->getMethod(), comp());
2310
if (!thunk)
2311
thunk = fej9->setJ2IThunk(methodSymbol->getMethod(), TR::PPCCallSnippet::generateVIThunk(callNode, sizeOfArguments, cg()), comp());
2312
2313
bool callIsSafe = methodSymRef != comp()->getSymRefTab()->findObjectNewInstanceImplSymbol();
2314
2315
if (methodSymbol->isVirtual())
2316
{
2317
// Handle unresolved/AOT virtual calls first
2318
//
2319
if (methodSymRef->isUnresolved() || comp()->compileRelocatableCode())
2320
{
2321
TR::Register *vftReg = evaluateUpToVftChild(callNode, cg());
2322
TR::addDependency(dependencies, vftReg, TR::RealRegister::NoReg, TR_GPR, cg());
2323
2324
TR::LabelSymbol *snippetLabel = generateLabelSymbol(cg());
2325
TR::Snippet *snippet = new (trHeapMemory()) TR::PPCVirtualUnresolvedSnippet(cg(), callNode, snippetLabel, sizeOfArguments, doneLabel);
2326
cg()->addSnippet(snippet);
2327
2328
generateTrg1Src1Instruction(cg(), TR::InstOpCode::mr, callNode, gr12, vftReg);
2329
2330
// These two instructions will be ultimately modified to load the
2331
// method pointer. The branch should be a no-op if the offset turns
2332
// out to be within range (for most cases).
2333
generateLabelInstruction(cg(), TR::InstOpCode::b, callNode, snippetLabel);
2334
generateTrg1MemInstruction(cg(),TR::InstOpCode::Op_load, callNode, gr12, TR::MemoryReference::createWithDisplacement(cg(), gr12, 0, TR::Compiler->om.sizeofReferenceAddress()));
2335
2336
generateSrc1Instruction(cg(), TR::InstOpCode::mtctr, callNode, gr12);
2337
TR::Instruction *gcPoint = generateInstruction(cg(), TR::InstOpCode::bctrl, callNode);
2338
generateDepLabelInstruction(cg(), TR::InstOpCode::label, callNode, doneLabel, dependencies);
2339
2340
gcPoint->PPCNeedsGCMap(regMapForGC);
2341
snippet->gcMap().setGCRegisterMask(regMapForGC);
2342
return;
2343
}
2344
2345
// Handle guarded devirtualization next
2346
//
2347
if (callIsSafe)
2348
{
2349
TR::ResolvedMethodSymbol *resolvedMethodSymbol = methodSymRef->getSymbol()->getResolvedMethodSymbol();
2350
TR_ResolvedMethod *resolvedMethod = resolvedMethodSymbol->getResolvedMethod();
2351
2352
if (comp()->performVirtualGuardNOPing() &&
2353
comp()->isVirtualGuardNOPingRequired() &&
2354
!resolvedMethod->isInterpreted() &&
2355
!callNode->isTheVirtualCallNodeForAGuardedInlinedCall())
2356
{
2357
TR_VirtualGuard *virtualGuard = NULL;
2358
2359
if (!resolvedMethod->virtualMethodIsOverridden() &&
2360
!resolvedMethod->isAbstract())
2361
{
2362
virtualGuard = TR_VirtualGuard::createGuardedDevirtualizationGuard(TR_NonoverriddenGuard, comp(), callNode);
2363
}
2364
else
2365
{
2366
TR_DevirtualizedCallInfo *devirtualizedCallInfo = comp()->findDevirtualizedCall(callNode);
2367
TR_OpaqueClassBlock *refinedThisClass = devirtualizedCallInfo ? devirtualizedCallInfo->_thisType : NULL;
2368
TR_OpaqueClassBlock *thisClass = refinedThisClass ? refinedThisClass : resolvedMethod->containingClass();
2369
2370
TR_PersistentCHTable *chTable = comp()->getPersistentInfo()->getPersistentCHTable();
2371
/* Devirtualization is not currently supported for AOT compilations */
2372
if (thisClass && TR::Compiler->cls.isAbstractClass(comp(), thisClass) && !comp()->compileRelocatableCode())
2373
{
2374
TR_ResolvedMethod *calleeMethod = chTable->findSingleAbstractImplementer(thisClass, methodSymRef->getOffset(), methodSymRef->getOwningMethod(comp()), comp());
2375
if (calleeMethod &&
2376
(comp()->isRecursiveMethodTarget(calleeMethod) ||
2377
!calleeMethod->isInterpreted() ||
2378
calleeMethod->isJITInternalNative()))
2379
{
2380
resolvedMethod = calleeMethod;
2381
virtualGuard = TR_VirtualGuard::createGuardedDevirtualizationGuard(TR_AbstractGuard, comp(), callNode);
2382
}
2383
}
2384
else if (refinedThisClass &&
2385
resolvedMethod->virtualMethodIsOverridden() &&
2386
!chTable->isOverriddenInThisHierarchy(resolvedMethod, refinedThisClass, methodSymRef->getOffset(), comp()))
2387
{
2388
TR_ResolvedMethod *calleeMethod = methodSymRef->getOwningMethod(comp())->getResolvedVirtualMethod(comp(), refinedThisClass, methodSymRef->getOffset());
2389
if (calleeMethod &&
2390
(comp()->isRecursiveMethodTarget(calleeMethod) ||
2391
!calleeMethod->isInterpreted() ||
2392
calleeMethod->isJITInternalNative()))
2393
{
2394
resolvedMethod = calleeMethod;
2395
virtualGuard = TR_VirtualGuard::createGuardedDevirtualizationGuard(TR_HierarchyGuard, comp(), callNode);
2396
}
2397
}
2398
}
2399
2400
// If we have a virtual call guard generate a direct call
2401
// in the inline path and the virtual call out of line.
2402
// If the guard is later patched we'll go out of line path.
2403
//
2404
if (virtualGuard)
2405
{
2406
TR::Node *vftNode = callNode->getFirstChild();
2407
TR::Register *vftReg = NULL;
2408
2409
// We prefer to evaluate the VFT child in the out of line path if possible, but if we can't do it then, do it now instead
2410
if (vftNode->getReferenceCount() > 1 || vftNode->getRegister())
2411
{
2412
vftReg = evaluateUpToVftChild(callNode, cg());
2413
TR::addDependency(dependencies, vftReg, TR::RealRegister::NoReg, TR_GPR, cg());
2414
}
2415
else
2416
{
2417
// If we push evaluation of the VFT node off to the outlined code section we have to make sure that any of it's children
2418
// that are needed later are still evaluated. We could, in theory skip evaluating children with refcount == 1 for the same
2419
// reason as above, but would have to then look at the child's children, and so on, so just evaluate the VFT's children here and now.
2420
for (uint32_t i = 0; i < vftNode->getNumChildren(); i++)
2421
cg()->evaluate(vftNode->getChild(i));
2422
}
2423
2424
TR::LabelSymbol *virtualCallLabel = generateLabelSymbol(cg());
2425
generateVirtualGuardNOPInstruction(cg(), callNode, virtualGuard->addNOPSite(), new (trHeapMemory()) TR::RegisterDependencyConditions(0, 0, trMemory()), virtualCallLabel);
2426
if (comp()->getOption(TR_EnableHCR))
2427
{
2428
TR_VirtualGuard *HCRGuard = TR_VirtualGuard::createGuardedDevirtualizationGuard(TR_HCRGuard, comp(), callNode);
2429
generateVirtualGuardNOPInstruction(cg(), callNode, HCRGuard->addNOPSite(), new (trHeapMemory()) TR::RegisterDependencyConditions(0, 0, trMemory()), virtualCallLabel);
2430
}
2431
if (resolvedMethod != resolvedMethodSymbol->getResolvedMethod())
2432
{
2433
methodSymRef = comp()->getSymRefTab()->findOrCreateMethodSymbol(methodSymRef->getOwningMethodIndex(),
2434
-1,
2435
resolvedMethod,
2436
TR::MethodSymbol::Virtual);
2437
methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();
2438
resolvedMethodSymbol = methodSymbol->getResolvedMethodSymbol();
2439
resolvedMethod = resolvedMethodSymbol->getResolvedMethod();
2440
}
2441
uintptr_t methodAddress = comp()->isRecursiveMethodTarget(resolvedMethod) ? 0 : (uintptr_t)resolvedMethod->startAddressForJittedMethod();
2442
TR::Instruction *gcPoint = generateDepImmSymInstruction(cg(), TR::InstOpCode::bl, callNode, methodAddress,
2443
new (trHeapMemory()) TR::RegisterDependencyConditions(0, 0, trMemory()), methodSymRef);
2444
generateDepLabelInstruction(cg(), TR::InstOpCode::label, callNode, doneLabel, dependencies);
2445
gcPoint->PPCNeedsGCMap(regMapForGC);
2446
fej9->reserveTrampolineIfNecessary(comp(), methodSymRef, false);
2447
2448
// Out of line virtual call
2449
//
2450
TR_PPCOutOfLineCodeSection *virtualCallOOL = new (trHeapMemory()) TR_PPCOutOfLineCodeSection(virtualCallLabel, doneLabel, cg());
2451
2452
virtualCallOOL->swapInstructionListsWithCompilation();
2453
TR::Instruction *OOLLabelInstr = generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, virtualCallLabel);
2454
2455
// XXX: Temporary fix, OOL instruction stream does not pick up live locals or monitors correctly.
2456
TR_ASSERT(!OOLLabelInstr->getLiveLocals() && !OOLLabelInstr->getLiveMonitors(), "Expecting first OOL instruction to not have live locals/monitors info");
2457
OOLLabelInstr->setLiveLocals(gcPoint->getLiveLocals());
2458
OOLLabelInstr->setLiveMonitors(gcPoint->getLiveMonitors());
2459
2460
TR::RegisterDependencyConditions *outlinedCallDeps;
2461
if (!vftReg)
2462
{
2463
vftReg = evaluateUpToVftChild(callNode, cg());
2464
outlinedCallDeps = new (trHeapMemory()) TR::RegisterDependencyConditions(1, 1, trMemory());
2465
// Normally we don't care which reg the VFT gets, but in this case we don't want to undo the assignments done by the main deps so we choose a reg that we know will not be needed
2466
TR::addDependency(outlinedCallDeps, vftReg, TR::RealRegister::gr11, TR_GPR, cg());
2467
}
2468
else
2469
outlinedCallDeps = new (trHeapMemory()) TR::RegisterDependencyConditions(0, 0, trMemory());
2470
2471
2472
buildVirtualCall(cg(), callNode, vftReg, gr12, regMapForGC);
2473
2474
TR::LabelSymbol *doneOOLLabel = generateLabelSymbol(cg());
2475
generateDepLabelInstruction(cg(), TR::InstOpCode::label, callNode, doneOOLLabel, outlinedCallDeps);
2476
generateLabelInstruction(cg(), TR::InstOpCode::b, callNode, doneLabel);
2477
virtualCallOOL->swapInstructionListsWithCompilation();
2478
cg()->getPPCOutOfLineCodeSectionList().push_front(virtualCallOOL);
2479
2480
return;
2481
}
2482
}
2483
}
2484
}
2485
2486
// Profile-driven virtual and interface calls
2487
//
2488
// If the top value dominates everything else, generate a single static
2489
// PIC call inline and a virtual call or dynamic PIC call out of line.
2490
//
2491
// Otherwise generate a reasonable amount of static PIC calls and a
2492
// virtual call or dynamic PIC call all inline.
2493
//
2494
TR::Register *vftReg = evaluateUpToVftChild(callNode, cg());
2495
TR::addDependency(dependencies, vftReg, TR::RealRegister::NoReg, TR_GPR, cg());
2496
2497
if (callIsSafe && !callNode->isTheVirtualCallNodeForAGuardedInlinedCall() && !comp()->getOption(TR_DisableInterpreterProfiling))
2498
{
2499
static char *maxVirtualStaticPICsString = feGetEnv("TR_ppcMaxVirtualStaticPICs");
2500
static uint32_t maxVirtualStaticPICs = maxVirtualStaticPICsString ? atoi(maxVirtualStaticPICsString) : 1;
2501
static char *maxInterfaceStaticPICsString = feGetEnv("TR_ppcMaxInterfaceStaticPICs");
2502
static uint32_t maxInterfaceStaticPICs = maxInterfaceStaticPICsString ? atoi(maxInterfaceStaticPICsString) : 1;
2503
2504
TR_ScratchList<J9::PPCPICItem> values(cg()->trMemory());
2505
const uint32_t maxStaticPICs = methodSymbol->isInterface() ? maxInterfaceStaticPICs : maxVirtualStaticPICs;
2506
2507
if (getProfiledCallSiteInfo(cg(), callNode, maxStaticPICs, values))
2508
{
2509
ListIterator<J9::PPCPICItem> i(&values);
2510
J9::PPCPICItem *pic = i.getFirst();
2511
2512
// If this value is dominant, optimize exclusively for it
2513
if (pic->_frequency > MAX_PROFILED_CALL_FREQUENCY)
2514
{
2515
TR::LabelSymbol *slowCallLabel = generateLabelSymbol(cg());
2516
2517
TR::Instruction *gcPoint = buildStaticPICCall(cg(), callNode, (uintptr_t)pic->_clazz, pic->_method,
2518
vftReg, gr11, cr0, slowCallLabel, regMapForGC);
2519
generateDepLabelInstruction(cg(), TR::InstOpCode::label, callNode, doneLabel, dependencies);
2520
2521
// Out of line virtual/interface call
2522
//
2523
TR_PPCOutOfLineCodeSection *slowCallOOL = new (trHeapMemory()) TR_PPCOutOfLineCodeSection(slowCallLabel, doneLabel, cg());
2524
2525
slowCallOOL->swapInstructionListsWithCompilation();
2526
TR::Instruction *OOLLabelInstr = generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, slowCallLabel);
2527
2528
// XXX: Temporary fix, OOL instruction stream does not pick up live locals or monitors correctly.
2529
TR_ASSERT(!OOLLabelInstr->getLiveLocals() && !OOLLabelInstr->getLiveMonitors(), "Expecting first OOL instruction to not have live locals/monitors info");
2530
OOLLabelInstr->setLiveLocals(gcPoint->getLiveLocals());
2531
OOLLabelInstr->setLiveMonitors(gcPoint->getLiveMonitors());
2532
2533
TR::LabelSymbol *doneOOLLabel = generateLabelSymbol(cg());
2534
2535
if (methodSymbol->isInterface())
2536
{
2537
TR::LabelSymbol *ifcSnippetLabel = generateLabelSymbol(cg());
2538
TR::PPCInterfaceCallSnippet *ifcSnippet = new (trHeapMemory()) TR::PPCInterfaceCallSnippet(cg(), callNode, ifcSnippetLabel, sizeOfArguments, doneOOLLabel, (uint8_t *)thunk);
2539
2540
cg()->addSnippet(ifcSnippet);
2541
buildInterfaceCall(cg(), callNode, vftReg, gr0, gr11, gr12, cr0, ifcSnippet, regMapForGC);
2542
}
2543
else
2544
{
2545
buildVirtualCall(cg(), callNode, vftReg, gr12, regMapForGC);
2546
}
2547
2548
generateDepLabelInstruction(cg(), TR::InstOpCode::label, callNode, doneOOLLabel, new (trHeapMemory()) TR::RegisterDependencyConditions(0, 0, trMemory()));
2549
generateLabelInstruction(cg(), TR::InstOpCode::b, callNode, doneLabel);
2550
slowCallOOL->swapInstructionListsWithCompilation();
2551
cg()->getPPCOutOfLineCodeSectionList().push_front(slowCallOOL);
2552
2553
return;
2554
}
2555
else
2556
{
2557
// Build multiple static PIC calls
2558
while (pic)
2559
{
2560
TR::LabelSymbol *nextLabel = generateLabelSymbol(cg());
2561
2562
buildStaticPICCall(cg(), callNode, (uintptr_t)pic->_clazz, pic->_method,
2563
vftReg, gr11, cr0, nextLabel, regMapForGC);
2564
generateLabelInstruction(cg(), TR::InstOpCode::b, callNode, doneLabel);
2565
generateLabelInstruction(cg(), TR::InstOpCode::label, callNode, nextLabel);
2566
pic = i.getNext();
2567
}
2568
// Regular virtual/interface call will be built below
2569
}
2570
}
2571
}
2572
2573
// Finally, regular virtual and interface calls
2574
//
2575
if (methodSymbol->isInterface())
2576
{
2577
TR::LabelSymbol *ifcSnippetLabel = generateLabelSymbol(cg());
2578
TR::PPCInterfaceCallSnippet *ifcSnippet = new (trHeapMemory()) TR::PPCInterfaceCallSnippet(cg(), callNode, ifcSnippetLabel, sizeOfArguments, doneLabel, (uint8_t *)thunk);
2579
2580
cg()->addSnippet(ifcSnippet);
2581
buildInterfaceCall(cg(), callNode, vftReg, gr0, gr11, gr12, cr0, ifcSnippet, regMapForGC);
2582
}
2583
else
2584
{
2585
buildVirtualCall(cg(), callNode, vftReg, gr12, regMapForGC);
2586
}
2587
generateDepLabelInstruction(cg(), TR::InstOpCode::label, callNode, doneLabel, dependencies);
2588
}
2589
2590
void inlineCharacterIsMethod(TR::Node *node, TR::MethodSymbol* methodSymbol, TR::CodeGenerator *cg, TR::LabelSymbol *&doneLabel)
2591
{
2592
TR::Compilation *comp = cg->comp();
2593
2594
TR::LabelSymbol *inRangeLabel = generateLabelSymbol(cg);
2595
TR::Register *cnd0Reg = cg->allocateRegister(TR_CCR);
2596
TR::Register *cnd1Reg = cg->allocateRegister(TR_CCR);
2597
TR::Register *cnd2Reg = cg->allocateRegister(TR_CCR);
2598
TR::Register *srcReg = cg->evaluate(node->getFirstChild());
2599
TR::Register *rangeReg = cg->allocateRegister(TR_GPR);
2600
TR::Register *returnRegister = cg->allocateRegister(TR_GPR);
2601
TR::Register *tmpReg = cg->allocateRegister(TR_GPR);
2602
2603
TR::RegisterDependencyConditions *dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(6, 6, cg->trMemory());
2604
TR::addDependency(dependencies, srcReg, TR::RealRegister::NoReg, TR_GPR, cg);
2605
TR::addDependency(dependencies, rangeReg, TR::RealRegister::NoReg, TR_GPR, cg);
2606
TR::addDependency(dependencies, returnRegister, TR::RealRegister::gr3, TR_GPR, cg);
2607
TR::addDependency(dependencies, cnd0Reg, TR::RealRegister::cr0, TR_CCR, cg);
2608
TR::addDependency(dependencies, cnd1Reg, TR::RealRegister::NoReg, TR_CCR, cg);
2609
TR::addDependency(dependencies, cnd2Reg, TR::RealRegister::NoReg, TR_CCR, cg);
2610
2611
int32_t imm = (TR::RealRegister::CRCC_GT << TR::RealRegister::pos_RT | TR::RealRegister::CRCC_GT << TR::RealRegister::pos_RA | TR::RealRegister::CRCC_GT << TR::RealRegister::pos_RB);
2612
2613
int64_t mask = 0xFFFF00;
2614
if (methodSymbol->getRecognizedMethod() == TR::java_lang_Character_isLetter ||
2615
methodSymbol->getRecognizedMethod() == TR::java_lang_Character_isAlphabetic )
2616
{
2617
mask = 0xFFFF80; // mask for ASCII
2618
}
2619
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm_r, node, tmpReg, srcReg, 0, mask); // set cnd0Reg(cr0)
2620
2621
switch(methodSymbol->getRecognizedMethod())
2622
{
2623
case TR::java_lang_Character_isDigit:
2624
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, rangeReg, 0x3930);
2625
generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cmprb, node, cnd1Reg, srcReg, rangeReg, 0);
2626
break;
2627
case TR::java_lang_Character_isAlphabetic:
2628
case TR::java_lang_Character_isLetter:
2629
//ASCII only
2630
generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, node, rangeReg, 0x7A61);
2631
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, rangeReg, rangeReg, 0x5A41);
2632
generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cmprb, node, cnd1Reg, srcReg, rangeReg, 1);
2633
break;
2634
case TR::java_lang_Character_isWhitespace:
2635
generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, node, rangeReg, 0x0D09);
2636
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, rangeReg, rangeReg, 0x201C);
2637
generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cmprb, node, cnd1Reg, srcReg, rangeReg, 1);
2638
break;
2639
case TR::java_lang_Character_isUpperCase:
2640
generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, node, rangeReg, 0x5A41);
2641
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, rangeReg, rangeReg, 0xD6C0);
2642
generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cmprb, node, cnd1Reg, srcReg, rangeReg, 1);
2643
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, rangeReg, (int16_t)0xDED8);
2644
generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cmprb, node, cnd2Reg, srcReg, rangeReg, 0);
2645
generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cror, node, cnd1Reg, cnd2Reg, cnd1Reg, imm);
2646
break;
2647
case TR::java_lang_Character_isLowerCase:
2648
loadConstant(cg, node, (int32_t)0x7A61F6DF, rangeReg);
2649
generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cmprb, node, cnd1Reg, srcReg, rangeReg, 1);
2650
loadConstant(cg, node, (int32_t)0xFFFFFFF8, rangeReg);
2651
generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cmprb, node, cnd2Reg, srcReg, rangeReg, 0);
2652
generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cror, node, cnd1Reg, cnd2Reg, cnd1Reg, imm);
2653
loadConstant(cg, node, (int64_t)0xFFFFFFFFFFAAB5BA, rangeReg);
2654
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmpeqb, node, cnd2Reg, srcReg, rangeReg);
2655
generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::cror, node, cnd1Reg, cnd2Reg, cnd1Reg, imm);
2656
break;
2657
}
2658
generateTrg1Src1Instruction(cg, TR::InstOpCode::setb, node, returnRegister, cnd1Reg);
2659
2660
generateDepConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, cnd0Reg, dependencies);
2661
2662
dependencies->stopUsingDepRegs(cg);
2663
cg->stopUsingRegister(returnRegister);
2664
cg->stopUsingRegister(cnd0Reg);
2665
cg->stopUsingRegister(cnd1Reg);
2666
cg->stopUsingRegister(cnd2Reg);
2667
cg->stopUsingRegister(srcReg);
2668
cg->stopUsingRegister(rangeReg);
2669
cg->stopUsingRegister(tmpReg);
2670
}
2671
2672
void J9::Power::PrivateLinkage::buildDirectCall(TR::Node *callNode,
2673
TR::SymbolReference *callSymRef,
2674
TR::RegisterDependencyConditions *dependencies,
2675
const TR::PPCLinkageProperties &pp,
2676
int32_t argSize)
2677
{
2678
TR::Instruction *gcPoint;
2679
TR::MethodSymbol *callSymbol = callSymRef->getSymbol()->castToMethodSymbol();
2680
TR::ResolvedMethodSymbol *sym = callSymbol->getResolvedMethodSymbol();
2681
TR_ResolvedMethod *vmm = (sym==NULL)?NULL:sym->getResolvedMethod();
2682
bool myself = comp()->isRecursiveMethodTarget(vmm);
2683
2684
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp()->fe());
2685
2686
if (callSymRef->getReferenceNumber() >= TR_PPCnumRuntimeHelpers)
2687
fej9->reserveTrampolineIfNecessary(comp(), callSymRef, false);
2688
2689
bool forceUnresolvedDispatch = !fej9->isResolvedDirectDispatchGuaranteed(comp());
2690
if ((callSymbol->isJITInternalNative() ||
2691
(!callSymRef->isUnresolved() && !callSymbol->isInterpreted() && ((forceUnresolvedDispatch && callSymbol->isHelper()) || !forceUnresolvedDispatch))))
2692
{
2693
gcPoint = generateDepImmSymInstruction(cg(), TR::InstOpCode::bl, callNode,
2694
myself?0:(uintptr_t)callSymbol->getMethodAddress(),
2695
dependencies, callSymRef?callSymRef:callNode->getSymbolReference());
2696
}
2697
else
2698
{
2699
TR::LabelSymbol *label = generateLabelSymbol(cg());
2700
TR::Snippet *snippet;
2701
2702
if (callSymRef->isUnresolved() || forceUnresolvedDispatch)
2703
{
2704
snippet = new (trHeapMemory()) TR::PPCUnresolvedCallSnippet(cg(), callNode, label, argSize);
2705
}
2706
else
2707
{
2708
snippet = new (trHeapMemory()) TR::PPCCallSnippet(cg(), callNode, label, callSymRef, argSize);
2709
snippet->gcMap().setGCRegisterMask(pp.getPreservedRegisterMapForGC());
2710
}
2711
2712
cg()->addSnippet(snippet);
2713
gcPoint = generateDepImmSymInstruction(cg(), TR::InstOpCode::bl, callNode,
2714
0,
2715
dependencies,
2716
new (trHeapMemory()) TR::SymbolReference(comp()->getSymRefTab(), label),
2717
snippet);
2718
2719
// Nop is necessary due to confusion when resolving shared slots at a transition
2720
if (callSymRef->isOSRInductionHelper())
2721
cg()->generateNop(callNode);
2722
}
2723
2724
// Helper linkage needs to cover volatiles in the GC map at this point because, unlike private linkage calls,
2725
// volatiles are not spilled prior to the call.
2726
gcPoint->PPCNeedsGCMap(callSymbol->getLinkageConvention() == TR_Helper ? 0xffffffff : pp.getPreservedRegisterMapForGC());
2727
}
2728
2729
2730
TR::Register *J9::Power::PrivateLinkage::buildDirectDispatch(TR::Node *callNode)
2731
{
2732
TR::SymbolReference *callSymRef = callNode->getSymbolReference();
2733
2734
const TR::PPCLinkageProperties &pp = getProperties();
2735
TR::RegisterDependencyConditions *dependencies =
2736
new (trHeapMemory()) TR::RegisterDependencyConditions(
2737
pp.getNumberOfDependencyGPRegisters(),
2738
pp.getNumberOfDependencyGPRegisters(), trMemory());
2739
2740
TR::Register *returnRegister=NULL;
2741
TR::LabelSymbol *doneLabel = generateLabelSymbol(cg());
2742
2743
// SG - start
2744
int32_t argSize = buildArgs(callNode, dependencies);
2745
bool inlinedCharacterIsMethod = false;
2746
if (comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P9) && comp()->target().is64Bit())
2747
{
2748
switch(callNode->getSymbol()->castToMethodSymbol()->getRecognizedMethod())
2749
{
2750
case TR::java_lang_Character_isDigit:
2751
case TR::java_lang_Character_isLetter:
2752
case TR::java_lang_Character_isUpperCase:
2753
case TR::java_lang_Character_isLowerCase:
2754
case TR::java_lang_Character_isWhitespace:
2755
case TR::java_lang_Character_isAlphabetic:
2756
inlinedCharacterIsMethod = true;
2757
inlineCharacterIsMethod(callNode, callNode->getSymbol()->castToMethodSymbol(), cg(), doneLabel);
2758
break;
2759
}
2760
}
2761
2762
buildDirectCall(callNode, callSymRef, dependencies, pp, argSize);
2763
// SG - end
2764
2765
cg()->machine()->setLinkRegisterKilled(true);
2766
cg()->setHasCall();
2767
2768
TR::Register *lowReg=NULL, *highReg=NULL;
2769
switch(callNode->getOpCodeValue())
2770
{
2771
case TR::icall:
2772
case TR::acall:
2773
returnRegister = dependencies->searchPostConditionRegister(
2774
pp.getIntegerReturnRegister());
2775
break;
2776
case TR::lcall:
2777
{
2778
if (comp()->target().is64Bit())
2779
returnRegister = dependencies->searchPostConditionRegister(
2780
pp.getLongReturnRegister());
2781
else
2782
{
2783
lowReg = dependencies->searchPostConditionRegister(
2784
pp.getLongLowReturnRegister());
2785
highReg = dependencies->searchPostConditionRegister(
2786
pp.getLongHighReturnRegister());
2787
2788
returnRegister = cg()->allocateRegisterPair(lowReg, highReg);
2789
}
2790
}
2791
break;
2792
case TR::fcall:
2793
case TR::dcall:
2794
returnRegister = dependencies->searchPostConditionRegister(
2795
pp.getFloatReturnRegister());
2796
if (callNode->getDataType() == TR::Float)
2797
returnRegister->setIsSinglePrecision();
2798
break;
2799
case TR::call:
2800
returnRegister = NULL;
2801
break;
2802
default:
2803
returnRegister = NULL;
2804
TR_ASSERT(0, "Unknown direct call Opcode.");
2805
}
2806
2807
if (inlinedCharacterIsMethod)
2808
{
2809
generateDepLabelInstruction(cg(), TR::InstOpCode::label, callNode, doneLabel, dependencies->cloneAndFix(cg()));
2810
}
2811
2812
callNode->setRegister(returnRegister);
2813
2814
cg()->freeAndResetTransientLongs();
2815
dependencies->stopUsingDepRegs(cg(), lowReg==NULL?returnRegister:highReg, lowReg);
2816
return(returnRegister);
2817
}
2818
2819
TR::Register *J9::Power::PrivateLinkage::buildIndirectDispatch(TR::Node *callNode)
2820
{
2821
const TR::PPCLinkageProperties &pp = getProperties();
2822
TR::RegisterDependencyConditions *dependencies =
2823
new (trHeapMemory()) TR::RegisterDependencyConditions(
2824
pp.getNumberOfDependencyGPRegisters()+1,
2825
pp.getNumberOfDependencyGPRegisters()+1, trMemory());
2826
2827
int32_t argSize = buildArgs(callNode, dependencies);
2828
TR::Register *returnRegister;
2829
2830
buildVirtualDispatch(callNode, dependencies, argSize);
2831
cg()->machine()->setLinkRegisterKilled(true);
2832
cg()->setHasCall();
2833
2834
TR::Register *lowReg=NULL, *highReg;
2835
switch(callNode->getOpCodeValue())
2836
{
2837
case TR::icalli:
2838
case TR::acalli:
2839
returnRegister = dependencies->searchPostConditionRegister(
2840
pp.getIntegerReturnRegister());
2841
break;
2842
case TR::lcalli:
2843
{
2844
if (comp()->target().is64Bit())
2845
returnRegister = dependencies->searchPostConditionRegister(
2846
pp.getLongReturnRegister());
2847
else
2848
{
2849
lowReg = dependencies->searchPostConditionRegister(
2850
pp.getLongLowReturnRegister());
2851
highReg = dependencies->searchPostConditionRegister(
2852
pp.getLongHighReturnRegister());
2853
2854
returnRegister = cg()->allocateRegisterPair(lowReg, highReg);
2855
}
2856
}
2857
break;
2858
case TR::fcalli:
2859
case TR::dcalli:
2860
returnRegister = dependencies->searchPostConditionRegister(
2861
pp.getFloatReturnRegister());
2862
if (callNode->getDataType() == TR::Float)
2863
returnRegister->setIsSinglePrecision();
2864
break;
2865
case TR::calli:
2866
returnRegister = NULL;
2867
break;
2868
default:
2869
returnRegister = NULL;
2870
TR_ASSERT(0, "Unknown indirect call Opcode.");
2871
}
2872
2873
callNode->setRegister(returnRegister);
2874
2875
cg()->freeAndResetTransientLongs();
2876
dependencies->stopUsingDepRegs(cg(), lowReg==NULL?returnRegister:highReg, lowReg);
2877
return(returnRegister);
2878
}
2879
2880
TR::Register *J9::Power::PrivateLinkage::buildalloca(TR::Node *BIFCallNode)
2881
{
2882
TR_ASSERT(0,"J9::Power::PrivateLinkage does not support alloca.\n");
2883
return NULL;
2884
}
2885
2886
int32_t J9::Power::HelperLinkage::buildArgs(TR::Node *callNode,
2887
TR::RegisterDependencyConditions *dependencies)
2888
{
2889
return buildPrivateLinkageArgs(callNode, dependencies, _helperLinkage);
2890
}
2891
2892
TR::MemoryReference *J9::Power::PrivateLinkage::getOutgoingArgumentMemRef(int32_t argSize, TR::Register *argReg, TR::InstOpCode::Mnemonic opCode, TR::PPCMemoryArgument &memArg, uint32_t length, const TR::PPCLinkageProperties& properties)
2893
{
2894
TR::Machine *machine = cg()->machine();
2895
2896
TR::MemoryReference *result = TR::MemoryReference::createWithDisplacement(cg(), machine->getRealRegister(properties.getNormalStackPointerRegister()),
2897
argSize+getOffsetToFirstParm(), length);
2898
memArg.argRegister = argReg;
2899
memArg.argMemory = result;
2900
memArg.opCode = opCode;
2901
return(result);
2902
}
2903
2904