Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/arm/codegen/J9ARMEvaluator.cpp
6004 views
1
/*******************************************************************************
2
* Copyright (c) 2000, 2021 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21
*******************************************************************************/
22
23
#include <stdint.h>
24
#include "j9.h"
25
#include "j9cfg.h"
26
#include "j9consts.h"
27
#include "thrdsup.h"
28
#include "thrtypes.h"
29
#include "arm/codegen/ARMInstruction.hpp"
30
#include "arm/codegen/ARMOperand2.hpp"
31
#include "arm/codegen/J9ARMSnippet.hpp"
32
#include "codegen/CodeGenerator.hpp"
33
#include "codegen/CodeGeneratorUtils.hpp"
34
#include "codegen/GenerateInstructions.hpp"
35
#include "codegen/Machine.hpp"
36
#include "codegen/Linkage.hpp"
37
#include "codegen/Linkage_inlines.hpp"
38
#include "codegen/Snippet.hpp"
39
#include "codegen/TreeEvaluator.hpp"
40
#include "control/Recompilation.hpp"
41
#include "control/RecompilationInfo.hpp"
42
#include "env/jittypes.h"
43
#include "env/CompilerEnv.hpp"
44
#include "il/Node.hpp"
45
#include "il/Node_inlines.hpp"
46
#include "il/TreeTop.hpp"
47
#include "il/TreeTop_inlines.hpp"
48
#include "infra/Bit.hpp"
49
#include "env/VMJ9.h"
50
51
#ifdef J9VM_GC_ALIGN_OBJECTS
52
#define OBJECT_ALIGNMENT 8
53
#else
54
#define OBJECT_ALIGNMENT (TR::Compiler->om.sizeofReferenceAddress())
55
#endif
56
57
static inline TR::Instruction *genNullTest(TR::CodeGenerator *cg,
58
TR::Node *node,
59
TR::Register *objectReg,
60
TR::Register *scratchReg,
61
TR::Instruction *cursor)
62
{
63
TR::Instruction *instr;
64
uint32_t base, rotate;
65
if (constantIsImmed8r(NULLVALUE, &base, &rotate))
66
{
67
instr = generateSrc1ImmInstruction(cg, TR::InstOpCode::cmp, node, objectReg, base, rotate, cursor);
68
}
69
else
70
{
71
instr = armLoadConstant(node, NULLVALUE, scratchReg, cg, cursor);
72
instr = generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, objectReg, scratchReg, instr);
73
}
74
75
return instr;
76
}
77
78
79
static TR::Register *nonFixedDependency(TR::CodeGenerator *cg,
80
TR::RegisterDependencyConditions *conditions,
81
TR::Register *nonFixedReg,
82
TR_RegisterKinds kind)
83
{
84
if (nonFixedReg == NULL)
85
nonFixedReg = cg->allocateRegister(kind);
86
87
TR::addDependency(conditions, nonFixedReg, TR::RealRegister::NoReg, kind, cg);
88
return nonFixedReg;
89
}
90
91
static int32_t numberOfRegisterCandidate(TR::Node *depNode, TR_RegisterKinds kind)
92
{
93
int32_t idx, result = 0;
94
95
for (idx = 0; idx < depNode->getNumChildren(); idx++)
96
{
97
TR::Node *child = depNode->getChild(idx);
98
TR::Register *reg;
99
/*
100
* The direct child node has HighGlobalRegisterNumber even if it is PassThrough
101
* The child of PassThrough node has garbage data for HighGlobalRegisterNumber.
102
*/
103
TR_GlobalRegisterNumber highNumber = child->getHighGlobalRegisterNumber();
104
105
if (child->getOpCodeValue() == TR::PassThrough)
106
child = child->getFirstChild();
107
reg = child->getRegister();
108
if (reg != NULL && reg->getKind() == kind)
109
{
110
result += 1;
111
if (kind == TR_GPR && highNumber > -1)
112
result += 1;
113
}
114
}
115
return (result);
116
}
117
118
TR::Instruction *OMR::ARM::TreeEvaluator::generateVFTMaskInstruction(TR::CodeGenerator *cg, TR::Node *node, TR::Register *dstReg, TR::Register *srcReg, TR::Instruction *prev)
119
{
120
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
121
uintptr_t mask = TR::Compiler->om.maskOfObjectVftField();
122
123
if (~mask == 0)
124
{
125
// no mask instruction required
126
return prev;
127
}
128
else
129
{
130
return generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::bic, node, dstReg, srcReg, ~mask, 0, prev);
131
}
132
}
133
134
TR::Instruction *OMR::ARM::TreeEvaluator::generateVFTMaskInstruction(TR::CodeGenerator *cg, TR::Node *node, TR::Register *reg, TR::Instruction *prev)
135
{
136
return generateVFTMaskInstruction(cg, node, reg, reg, prev);
137
}
138
139
static TR::Instruction *genTestIsSuper(TR::CodeGenerator *cg,
140
TR::Node *node,
141
TR::Register *objClassReg,
142
TR::Register *castClassReg,
143
TR::Register *scratch1Reg,
144
TR::Register *scratch2Reg,
145
int32_t castClassDepth,
146
TR::LabelSymbol *failLabel,
147
TR::Instruction *cursor,
148
TR::LabelSymbol *doneLabel)
149
{
150
uint32_t base, rotate;
151
uint32_t shiftAmount = leadingZeroes(J9AccClassDepthMask);
152
int32_t superClassOffset = castClassDepth << 2;
153
bool outOfBound = (superClassOffset > UPPER_IMMED12 || superClassOffset < LOWER_IMMED12);
154
bool regDepth = !constantIsImmed8r(castClassDepth, &base, &rotate);
155
156
TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(objClassReg, offsetof(J9Class, classDepthAndFlags), cg);
157
cursor = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, scratch1Reg, tempMR, cursor);
158
159
cursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mvn, node, scratch2Reg, 0, 0, cursor);
160
161
TR_ARMOperand2 *operand2 = new (cg->trHeapMemory()) TR_ARMOperand2(ARMOp2RegLSRImmed, scratch2Reg, shiftAmount);
162
cursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::and_, node, scratch1Reg, scratch1Reg, operand2, cursor);
163
164
if (outOfBound || regDepth)
165
{
166
cursor = armLoadConstant(node, castClassDepth, scratch2Reg, cg, cursor);
167
cursor = generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, scratch1Reg, scratch2Reg, cursor);
168
}
169
else
170
{
171
cursor = generateSrc1ImmInstruction(cg, TR::InstOpCode::cmp, node, scratch1Reg, base, rotate, cursor);
172
}
173
174
if (failLabel)
175
{
176
cursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeLE, failLabel, cursor);
177
}
178
else
179
{
180
TR::SymbolReference *symRef = node->getSymbolReference();
181
cursor = generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)symRef->getMethodAddress(), NULL, symRef, NULL, NULL, ARMConditionCodeLE);
182
cursor->ARMNeedsGCMap(0xFFFFFFFF);
183
cg->machine()->setLinkRegisterKilled(true);
184
}
185
186
187
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(objClassReg, offsetof(J9Class,superclasses), cg);
188
cursor = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, scratch1Reg, tempMR, cursor);
189
190
if (outOfBound || regDepth)
191
{
192
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(scratch1Reg, scratch2Reg, 4, cg);
193
cursor = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, scratch1Reg, tempMR, cursor);
194
}
195
else
196
{
197
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(scratch1Reg, superClassOffset, cg);
198
cursor = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, scratch1Reg, tempMR, cursor);
199
}
200
201
cursor = generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, scratch1Reg, castClassReg, cursor);
202
return cursor;
203
}
204
205
206
TR::Register *OMR::ARM::TreeEvaluator::VMcheckcastEvaluator(TR::Node *node, TR::CodeGenerator *cg)
207
{
208
TR::Node *objNode = node->getFirstChild();
209
TR::Node *castClassNode = node->getSecondChild();
210
TR::SymbolReference *castClassSymRef = castClassNode->getSymbolReference();
211
TR::Compilation *comp = TR::comp();
212
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
213
214
TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(6, 6, cg->trMemory());
215
216
int32_t castClassDepth = -1;
217
bool testEqualClass = instanceOfOrCheckCastNeedEqualityTest(node, cg);
218
bool testCastClassIsSuper = instanceOfOrCheckCastNeedSuperTest(node, cg);
219
TR::StaticSymbol *castClassSym;
220
TR_OpaqueClassBlock *clazz;
221
222
bool isCheckCastOrNullCheck = (node->getOpCodeValue() == TR::checkcastAndNULLCHK);
223
224
if (testCastClassIsSuper)
225
{
226
castClassSym = castClassSymRef->getSymbol()->getStaticSymbol();
227
clazz = (TR_OpaqueClassBlock *) castClassSym->getStaticAddress();
228
if (fej9->classHasBeenExtended(clazz) || comp->getMethodHotness() < warm || !comp->isRecompilationEnabled() )
229
{
230
castClassDepth = TR::Compiler->cls.classDepthOf(clazz);
231
}
232
else
233
{
234
testCastClassIsSuper = false;
235
}
236
}
237
238
TR::Register *objReg = cg->evaluate(objNode);
239
TR::Register *castClassReg = cg->evaluate(castClassNode);
240
TR::Register *objClassReg = cg->allocateRegister();
241
242
TR::addDependency(deps, objReg, TR::RealRegister::gr1, TR_GPR, cg);
243
TR::addDependency(deps, castClassReg, TR::RealRegister::gr0, TR_GPR, cg);
244
245
cg->machine()->setLinkRegisterKilled(true);
246
247
if (!testEqualClass && !testCastClassIsSuper)
248
{
249
TR::SymbolReference *symRef = node->getSymbolReference();
250
TR::Instruction *gcPoint = generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uint32_t)symRef->getMethodAddress(), deps, symRef);
251
gcPoint->ARMNeedsGCMap(0xFFFFFFFF);
252
deps->stopAddingConditions();
253
cg->decReferenceCount(objNode);
254
cg->decReferenceCount(castClassNode);
255
return NULL;
256
}
257
258
TR::LabelSymbol *doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
259
260
TR::Instruction *gcPoint;
261
262
TR::addDependency(deps, objClassReg, TR::RealRegister::NoReg, TR_GPR, cg);
263
264
TR::Instruction *implicitExceptionPointInstr = NULL;
265
if (!objNode->isNonNull())
266
{
267
if (!isCheckCastOrNullCheck)
268
{
269
genNullTest(cg, node, objReg, objClassReg, NULL);
270
generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, doneLabel);
271
}
272
}
273
274
implicitExceptionPointInstr = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, objClassReg,
275
new (cg->trHeapMemory()) TR::MemoryReference(objReg, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), cg));
276
generateVFTMaskInstruction(cg, node, objClassReg);
277
278
TR::SymbolReference *symRef = node->getSymbolReference();
279
280
if (testEqualClass)
281
{
282
generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, objClassReg, castClassReg);
283
if (testCastClassIsSuper)
284
generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, doneLabel);
285
else
286
{
287
gcPoint = generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)symRef->getMethodAddress(), NULL, symRef, NULL, NULL, ARMConditionCodeNE);
288
gcPoint->ARMNeedsGCMap(0xFFFFFFFF);
289
}
290
}
291
292
if (testCastClassIsSuper)
293
{
294
TR::Register *scratch1Reg = cg->allocateRegister();
295
TR::Register *scratch2Reg = cg->allocateRegister();
296
TR::addDependency(deps, scratch1Reg, TR::RealRegister::NoReg, TR_GPR, cg);
297
TR::addDependency(deps, scratch2Reg, TR::RealRegister::NoReg, TR_GPR, cg);
298
299
genTestIsSuper(cg, node, objClassReg, castClassReg, scratch1Reg,
300
scratch2Reg, castClassDepth, NULL, NULL, doneLabel);
301
gcPoint = generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)symRef->getMethodAddress(), NULL, symRef, NULL, NULL, ARMConditionCodeNE);
302
gcPoint->ARMNeedsGCMap(0xFFFFFFFF);
303
}
304
305
if (isCheckCastOrNullCheck &&
306
implicitExceptionPointInstr &&
307
!objNode->isNonNull())
308
{
309
cg->setImplicitExceptionPoint(implicitExceptionPointInstr);
310
implicitExceptionPointInstr->setNeedsGCMap();
311
// find the bytecodeinfo of the
312
// NULLCHK that was compacted
313
TR::Node *implicitExceptionPointNode = comp->findNullChkInfo(node);
314
implicitExceptionPointInstr->setNode(implicitExceptionPointNode);
315
}
316
317
generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, deps);
318
deps->stopAddingConditions();
319
320
cg->decReferenceCount(objNode);
321
cg->decReferenceCount(castClassNode);
322
return NULL;
323
}
324
325
326
TR::Register *OMR::ARM::TreeEvaluator::VMifInstanceOfEvaluator(TR::Node *node, TR::CodeGenerator *cg)
327
{
328
TR::Compilation *comp = TR::comp();
329
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
330
bool branchOn1 = false;
331
332
TR::Register *resultReg = NULL;
333
TR::LabelSymbol *doneLabel = NULL;
334
TR::LabelSymbol *trueLabel = NULL;
335
TR::LabelSymbol *res0Label = NULL;
336
TR::LabelSymbol *res1Label = NULL;
337
338
TR::RegisterDependencyConditions *conditions = NULL;
339
TR::RegisterDependencyConditions *deps = NULL;
340
341
TR::ILOpCodes opCode = node->getOpCodeValue();
342
TR::Node *instanceOfNode = node->getFirstChild();
343
TR::Node *valueNode = node->getSecondChild();
344
TR::Node *depNode = node->getNumChildren() == 3 ? node->getChild(2) : NULL;
345
TR::Node *objectNode = instanceOfNode->getFirstChild();
346
TR::Node *castClassNode = instanceOfNode->getSecondChild();
347
int32_t value = valueNode->getInt();
348
int32_t numDeps = depNode ? depNode->getNumChildren() : 0;
349
int32_t castClassDepth = -1;
350
TR::SymbolReference *castClassSymRef = castClassNode->getSymbolReference();
351
TR::LabelSymbol *branchLabel = node->getBranchDestination()->getNode()->getLabel();
352
bool testEqualClass = instanceOfOrCheckCastNeedEqualityTest(instanceOfNode, cg);
353
bool testCastClassIsSuper = instanceOfOrCheckCastNeedSuperTest(instanceOfNode, cg);
354
bool isFinalClass = (castClassSymRef == NULL) ? false : castClassSymRef->isNonArrayFinal(comp);
355
bool needsHelperCall = TR::TreeEvaluator::instanceOfNeedHelperCall(testCastClassIsSuper, isFinalClass);
356
357
// If the result itself is assigned to a global register, we still have to do
358
// something special...
359
bool needResult = (instanceOfNode->getReferenceCount() > 1);
360
361
int32_t i;
362
if (depNode != NULL)
363
{
364
if (!needsHelperCall && numberOfRegisterCandidate(depNode, TR_GPR) + 6 > cg->getMaximumNumberOfGPRsAllowedAcrossEdge(node))
365
return (TR::Register *)1;
366
367
TR::ARMLinkageProperties properties = cg->getLinkage()->getProperties();
368
for (i = 0; i < depNode->getNumChildren(); i++)
369
{
370
TR::Node *childNode = depNode->getChild(i);
371
int32_t regIndex = cg->getGlobalRegister(depNode->getChild(i)->getGlobalRegisterNumber());
372
int32_t highIndex = childNode->getHighGlobalRegisterNumber();
373
374
if (needsHelperCall)
375
{
376
if (highIndex > -1)
377
highIndex = cg->getGlobalRegister(highIndex);
378
if (!properties.getPreserved((TR::RealRegister::RegNum) regIndex) || (highIndex > -1 && !properties.getPreserved((TR::RealRegister::RegNum) highIndex)))
379
return (TR::Register *)1;
380
}
381
else
382
{
383
// Below check code taken from PPC.
384
if (childNode->getOpCodeValue() == TR::PassThrough)
385
childNode = childNode->getFirstChild();
386
if ((childNode == instanceOfNode || childNode == castClassNode) && regIndex == TR::RealRegister::gr0)
387
return ((TR::Register *) 1);
388
}
389
}
390
}
391
392
if (testEqualClass || testCastClassIsSuper)
393
{
394
doneLabel = generateLabelSymbol(cg);
395
}
396
397
if ((opCode == TR::ificmpeq && value == 1) ||
398
(opCode != TR::ificmpeq && value == 0))
399
{
400
res0Label = doneLabel;
401
res1Label = branchLabel;
402
branchOn1 = true;
403
}
404
else
405
{
406
res0Label = branchLabel;
407
res1Label = doneLabel;
408
branchOn1 = false;
409
}
410
411
TR::Register *objectReg;
412
TR::Register *objClassReg;
413
TR::Register *castClassReg;
414
TR::Register *scratch1Reg;
415
TR::Register *scratch2Reg;
416
TR::Instruction *iCursor;
417
418
if (needsHelperCall)
419
{
420
TR::ILOpCodes childOpCode = instanceOfNode->getOpCodeValue();
421
422
TR::Node::recreate(instanceOfNode, TR::icall);
423
directCallEvaluator(instanceOfNode, cg);
424
TR::Node::recreate(instanceOfNode, childOpCode);
425
426
iCursor = cg->getAppendInstruction();
427
while (iCursor->getOpCodeValue() != TR::InstOpCode::bl)
428
iCursor = iCursor->getPrev();
429
conditions = iCursor->getDependencyConditions();
430
iCursor = iCursor->getPrev();
431
objectReg= conditions->searchPreConditionRegister(TR::RealRegister::gr1);
432
castClassReg = conditions->searchPreConditionRegister(TR::RealRegister::gr0);
433
scratch1Reg = conditions->searchPreConditionRegister(TR::RealRegister::gr2);
434
scratch2Reg = conditions->searchPreConditionRegister(TR::RealRegister::gr3);
435
objClassReg = conditions->searchPreConditionRegister(TR::RealRegister::gr4);
436
437
if (depNode !=NULL)
438
{
439
cg->evaluate(depNode);
440
deps = generateRegisterDependencyConditions(cg, depNode, 0, &iCursor);
441
}
442
443
if (testEqualClass || testCastClassIsSuper)
444
{
445
if (needResult)
446
{
447
resultReg = conditions->searchPreConditionRegister(TR::RealRegister::gr5);
448
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 0, 0, iCursor);
449
}
450
if (!objectNode->isNonNull())
451
{
452
iCursor = genNullTest(cg, objectNode, objectReg, scratch1Reg, iCursor);
453
iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, res0Label, iCursor);
454
}
455
}
456
}
457
else
458
{
459
bool earlyEval = (castClassNode->getOpCodeValue() != TR::loadaddr ||
460
castClassNode->getReferenceCount() > 1)?true:false;
461
bool objInDep = false, castClassInDep = false;
462
if (depNode != NULL)
463
{
464
cg->evaluate(depNode);
465
deps = generateRegisterDependencyConditions(cg, depNode, 6);
466
for (i = 0; i < numDeps; i++)
467
{
468
TR::Node *grNode = depNode->getChild(i);
469
if (grNode->getOpCodeValue() == TR::PassThrough)
470
grNode = grNode->getFirstChild();
471
if (grNode == objectNode)
472
objInDep = true;
473
if (grNode == castClassNode)
474
castClassInDep = true;
475
}
476
}
477
if (deps == NULL)
478
{
479
conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(6, 6, cg->trMemory());
480
}
481
else
482
{
483
conditions = deps;
484
}
485
486
if (needResult)
487
{
488
resultReg = nonFixedDependency(cg, conditions, NULL, TR_GPR);
489
}
490
491
objClassReg = nonFixedDependency(cg, conditions, NULL, TR_GPR);
492
493
objectReg = cg->evaluate(objectNode);
494
if (!objInDep)
495
objectReg = nonFixedDependency(cg, conditions, objectReg, TR_GPR);
496
497
if (earlyEval)
498
{
499
castClassReg = cg->evaluate(castClassNode);
500
if (!castClassInDep)
501
castClassReg = nonFixedDependency(cg, conditions, castClassReg, TR_GPR);
502
}
503
504
if (needResult)
505
{
506
generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 0, 0);
507
}
508
509
if (!objectNode->isNonNull())
510
{
511
genNullTest(cg, objectNode, objectReg, objClassReg, NULL);
512
generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, res0Label);
513
}
514
515
if (!earlyEval)
516
{
517
castClassReg = cg->evaluate(castClassNode);
518
if (!castClassInDep)
519
castClassReg = nonFixedDependency(cg, conditions, castClassReg, TR_GPR);
520
}
521
522
if (testCastClassIsSuper)
523
{
524
scratch1Reg = nonFixedDependency(cg, conditions, NULL, TR_GPR);
525
scratch2Reg = nonFixedDependency(cg, conditions, NULL, TR_GPR);
526
cg->stopUsingRegister(scratch1Reg);
527
cg->stopUsingRegister(scratch2Reg);
528
}
529
530
iCursor = cg->getAppendInstruction();
531
generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);
532
conditions->stopAddingConditions();
533
cg->decReferenceCount(objectNode);
534
cg->decReferenceCount(castClassNode);
535
}
536
537
if (testEqualClass || testCastClassIsSuper)
538
{
539
TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(objectReg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), cg);
540
iCursor = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, objClassReg, tempMR, iCursor);
541
iCursor = generateVFTMaskInstruction(cg, node, objClassReg, iCursor);
542
}
543
544
if (testEqualClass)
545
{
546
iCursor = generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, objClassReg, castClassReg, iCursor);
547
548
if (testCastClassIsSuper)
549
{
550
if (needResult)
551
{
552
trueLabel = generateLabelSymbol(cg);
553
iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, trueLabel, iCursor);
554
}
555
else
556
{
557
iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, res1Label, iCursor);
558
}
559
}
560
else if (needsHelperCall)
561
{
562
if (needResult)
563
{
564
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 1, 0, iCursor);
565
}
566
iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, res1Label, iCursor);
567
}
568
else
569
{
570
if (needResult)
571
{
572
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 1, 0, iCursor);
573
iCursor->setConditionCode(ARMConditionCodeEQ);
574
}
575
576
if (branchOn1)
577
{
578
iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, res1Label, iCursor);
579
}
580
else
581
{
582
iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, res0Label, iCursor);
583
}
584
}
585
}
586
587
if (testCastClassIsSuper)
588
{
589
TR::StaticSymbol *castClassSym;
590
591
castClassSym = castClassSymRef->getSymbol()->getStaticSymbol();
592
void * clazz = castClassSym->getStaticAddress();
593
castClassDepth = TR::Compiler->cls.classDepthOf((TR_OpaqueClassBlock *) clazz);
594
595
iCursor = genTestIsSuper(cg, node, objClassReg, castClassReg, scratch1Reg, scratch2Reg, castClassDepth, res0Label, iCursor, NULL);
596
iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, res0Label, iCursor);
597
if (trueLabel == NULL)
598
{
599
if (needResult)
600
{
601
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 1, 0, iCursor);
602
}
603
}
604
else
605
{
606
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, trueLabel, iCursor);
607
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 1, 0, iCursor);
608
}
609
610
if (branchOn1)
611
{
612
iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, res1Label, iCursor);
613
}
614
}
615
616
if (needsHelperCall)
617
{
618
TR::Register *callResult = instanceOfNode->getRegister();
619
TR::RegisterDependencyConditions *newDeps;
620
621
if (resultReg == NULL)
622
{
623
resultReg = callResult;
624
}
625
else
626
{
627
generateTrg1Src1Instruction(cg, TR::InstOpCode::mov, node, resultReg, callResult);
628
}
629
630
generateSrc1ImmInstruction(cg, TR::InstOpCode::cmp, node, resultReg, 0, 0);
631
632
if (depNode != NULL)
633
{
634
newDeps = conditions->cloneAndFix(cg, deps);
635
}
636
else
637
{
638
newDeps = conditions->cloneAndFix(cg);
639
}
640
641
if (branchOn1)
642
{
643
if (doneLabel == NULL)
644
generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, res1Label, newDeps);
645
else
646
generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, res1Label);
647
}
648
else
649
{
650
if (doneLabel == NULL)
651
generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, res0Label, newDeps);
652
else
653
generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, res0Label);
654
}
655
656
if (doneLabel != NULL)
657
{
658
generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, newDeps);
659
newDeps->stopAddingConditions();
660
}
661
662
#if 0 // TODO:PPC has this fixup. It maybe a fix to something so keeping here as note. See J9PPCEvaluator.cpp for reviveResultRegister() imple.
663
// We have to revive the resultReg here. Should revisit to see how to use registers better
664
// (e.g., reducing the chance of moving around).
665
if (resultReg != callResult)
666
reviveResultRegister(resultReg, callResult, cg);
667
#endif
668
}
669
670
if (resultReg != instanceOfNode->getRegister())
671
instanceOfNode->setRegister(resultReg);
672
cg->decReferenceCount(instanceOfNode);
673
cg->decReferenceCount(valueNode);
674
if (depNode != NULL)
675
cg->decReferenceCount(depNode);
676
node->setRegister(NULL);
677
return NULL;
678
}
679
680
681
TR::Register *OMR::ARM::TreeEvaluator::VMinstanceOfEvaluator(TR::Node *node, TR::CodeGenerator *cg)
682
{
683
TR::Compilation *comp = TR::comp();
684
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
685
TR::Register *objectReg, *castClassReg, *objClassReg;
686
TR::Register *resultReg, *scratch1Reg, *scratch2Reg;
687
TR::Instruction *iCursor;
688
TR::RegisterDependencyConditions *conditions;
689
TR::LabelSymbol *doneLabel, *trueLabel;
690
TR::Node *objectNode, *castClassNode;
691
int32_t castClassDepth = -1;
692
693
trueLabel = doneLabel = NULL;
694
resultReg = NULL;
695
objectNode = node->getFirstChild();
696
castClassNode = node->getSecondChild();
697
TR::SymbolReference * castClassSymRef = castClassNode->getSymbolReference();
698
bool testEqualClass = instanceOfOrCheckCastNeedEqualityTest(node, cg);
699
bool testCastClassIsSuper = instanceOfOrCheckCastNeedSuperTest(node, cg);
700
bool isFinalClass = (castClassSymRef == NULL) ? false : castClassSymRef->isNonArrayFinal(comp);
701
bool needsHelperCall = TR::TreeEvaluator::instanceOfNeedHelperCall(testCastClassIsSuper, isFinalClass);
702
703
if (needsHelperCall)
704
{
705
TR::ILOpCodes opCode = node->getOpCodeValue();
706
707
TR::Node::recreate(node, TR::icall);
708
directCallEvaluator(node, cg);
709
TR::Node::recreate(node, opCode);
710
711
iCursor = cg->getAppendInstruction();
712
while (iCursor->getOpCodeValue() != TR::InstOpCode::bl)
713
iCursor = iCursor->getPrev();
714
conditions = iCursor->getDependencyConditions();
715
iCursor = iCursor->getPrev();
716
objectReg= conditions->searchPreConditionRegister(
717
TR::RealRegister::gr1);
718
castClassReg = conditions->searchPreConditionRegister(
719
TR::RealRegister::gr0);
720
scratch1Reg = conditions->searchPreConditionRegister(
721
TR::RealRegister::gr2);
722
scratch2Reg = conditions->searchPreConditionRegister(
723
TR::RealRegister::gr3);
724
objClassReg = conditions->searchPreConditionRegister(
725
TR::RealRegister::gr4);
726
727
if (testEqualClass || testCastClassIsSuper)
728
{
729
doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
730
731
resultReg = conditions->searchPreConditionRegister(
732
TR::RealRegister::gr5);
733
734
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 0, 0, iCursor);
735
if (!objectNode->isNonNull())
736
{
737
iCursor = genNullTest(cg, objectNode, objectReg, scratch1Reg, iCursor);
738
iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, doneLabel, iCursor);
739
}
740
}
741
}
742
else
743
{
744
bool earlyEval = (castClassNode->getOpCodeValue() != TR::loadaddr ||
745
castClassNode->getReferenceCount() > 1)?true:false;
746
747
conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(6, 6, cg->trMemory());
748
749
resultReg = nonFixedDependency(cg, conditions, NULL, TR_GPR);
750
objClassReg = nonFixedDependency(cg, conditions, NULL, TR_GPR);
751
752
objectReg = cg->evaluate(objectNode);
753
objectReg = nonFixedDependency(cg, conditions, objectReg, TR_GPR);
754
if (earlyEval)
755
{
756
castClassReg = cg->evaluate(castClassNode);
757
castClassReg = nonFixedDependency(cg, conditions, castClassReg, TR_GPR);
758
}
759
760
doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
761
generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 0, 0);
762
if (!objectNode->isNonNull())
763
{
764
genNullTest(cg, objectNode, objectReg, objClassReg, NULL);
765
generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, doneLabel);
766
}
767
768
if (!earlyEval)
769
{
770
castClassReg = cg->evaluate(castClassNode);
771
castClassReg = nonFixedDependency(cg, conditions, castClassReg, TR_GPR);
772
}
773
774
if (testCastClassIsSuper)
775
{
776
scratch1Reg = nonFixedDependency(cg, conditions, NULL, TR_GPR);
777
scratch2Reg = nonFixedDependency(cg, conditions, NULL, TR_GPR);
778
}
779
780
iCursor = cg->getAppendInstruction();
781
generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);
782
cg->decReferenceCount(objectNode);
783
cg->decReferenceCount(castClassNode);
784
}
785
786
if (testEqualClass || testCastClassIsSuper)
787
{
788
TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(objectReg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), cg);
789
iCursor = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, objClassReg, tempMR, iCursor);
790
iCursor = generateVFTMaskInstruction(cg, node, objClassReg, iCursor);
791
}
792
793
if (testEqualClass)
794
{
795
iCursor = generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, objClassReg, castClassReg, iCursor);
796
797
if (testCastClassIsSuper)
798
{
799
trueLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
800
iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, trueLabel, iCursor);
801
}
802
else if (needsHelperCall)
803
{
804
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 1, 0, iCursor);
805
iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, doneLabel, iCursor);
806
}
807
else
808
{
809
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 1, 0, iCursor);
810
iCursor->setConditionCode(ARMConditionCodeEQ);
811
}
812
}
813
814
if (testCastClassIsSuper)
815
{
816
TR::StaticSymbol *castClassSym;
817
818
castClassSym = castClassSymRef->getSymbol()->getStaticSymbol();
819
void * clazz = castClassSym->getStaticAddress();
820
castClassDepth = TR::Compiler->cls.classDepthOf((TR_OpaqueClassBlock *) clazz);
821
822
iCursor = genTestIsSuper(cg, node, objClassReg, castClassReg, scratch1Reg, scratch2Reg, castClassDepth, doneLabel, iCursor, NULL);
823
824
// needHelperCall must be false, and the only consumer of "trueLabel" is a branch instruction
825
// with the exact same condition as required below. We can take advantage of this situation.
826
827
if (trueLabel != NULL)
828
{
829
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, trueLabel, iCursor);
830
}
831
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, resultReg, 1, 0, iCursor);
832
iCursor->setConditionCode(ARMConditionCodeEQ);
833
}
834
835
if (needsHelperCall)
836
{
837
TR::Register *callResult = node->getRegister();
838
if (resultReg == NULL)
839
{
840
resultReg = callResult;
841
}
842
else
843
{
844
generateTrg1Src1Instruction(cg, TR::InstOpCode::mov, node, resultReg, callResult);
845
generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions->cloneAndFix(cg));
846
}
847
}
848
if (resultReg != node->getRegister())
849
node->setRegister(resultReg);
850
return resultReg;
851
}
852
853
854
TR::Register *OMR::ARM::TreeEvaluator::VMmonexitEvaluator(TR::Node *node, TR::CodeGenerator *cg)
855
{
856
TR::Compilation *comp = TR::comp();
857
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
858
int32_t lwOffset = fej9->getByteOffsetToLockword(cg->getMonClass(node));
859
860
if ((comp->getOption(TR_FullSpeedDebug) /*&& !comp->getOption(TR_EnableLiveMonitorMetadata)*/) ||
861
comp->getOption(TR_DisableInlineMonExit) ||
862
lwOffset <= 0)
863
{
864
TR::ILOpCodes opCode = node->getOpCodeValue();
865
TR::Node::recreate(node, TR::call);
866
TR::Register *targetRegister = directCallEvaluator(node, cg);
867
TR::Node::recreate(node, opCode);
868
return targetRegister;
869
}
870
871
TR::Node *objNode = node->getFirstChild();
872
TR::Register *objReg = cg->evaluate(objNode);
873
TR::Register *monitorReg = cg->allocateRegister();
874
TR::Register *flagReg = cg->allocateRegister();
875
TR::Register *metaReg = cg->getMethodMetaDataRegister();
876
877
TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(3, 3, cg->trMemory());
878
TR::addDependency(deps, objReg, TR::RealRegister::gr0, TR_GPR, cg);
879
TR::addDependency(deps, monitorReg, TR::RealRegister::NoReg, TR_GPR, cg);
880
TR::addDependency(deps, flagReg, TR::RealRegister::NoReg, TR_GPR, cg);
881
882
TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(objReg, lwOffset, cg);
883
generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, monitorReg, tempMR);
884
generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, monitorReg, metaReg);
885
886
TR::Instruction *instr = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, flagReg, 0, 0);
887
instr->setConditionCode(ARMConditionCodeEQ);
888
889
if (cg->comp()->target().isSMP() && cg->comp()->target().cpu.id() != TR_DefaultARMProcessor)
890
{
891
//instr = generateInstruction(cg, (cg->comp()->target().cpu.id() == TR_ARMv6) ? TR::InstOpCode::dmb_v6 : TR::InstOpCode::dmb, node);
892
instr = generateInstruction(cg, TR::InstOpCode::dmb_v6 , node); // v7 version is unconditional
893
instr->setConditionCode(ARMConditionCodeEQ);
894
}
895
896
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(objReg, lwOffset, cg);
897
instr = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, flagReg);
898
instr->setConditionCode(ARMConditionCodeEQ);
899
900
// Branch to decLabel in snippet first
901
TR::LabelSymbol *decLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
902
TR::LabelSymbol *callLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
903
TR::LabelSymbol *doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
904
TR::Snippet *snippet = new (cg->trHeapMemory()) TR::ARMMonitorExitSnippet(cg, node, lwOffset, decLabel, callLabel, doneLabel);
905
906
generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, decLabel);
907
908
generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, deps);
909
cg->addSnippet(snippet);
910
doneLabel->setEndInternalControlFlow();
911
912
cg->decReferenceCount(objNode);
913
return NULL;
914
}
915
916
917
static void genHeapAlloc(TR::CodeGenerator *cg,
918
TR::Node *node,
919
TR::Instruction * &iCursor,
920
bool isVariableLen,
921
TR::Register *enumReg,
922
TR::Register *resReg,
923
TR::Register *zeroReg,
924
TR::Register *dataSizeReg,
925
TR::Register *heapTopReg,
926
TR::Register *sizeReg,
927
TR::LabelSymbol *callLabel,
928
int32_t allocSize)
929
{
930
if (cg->comp()->getOptions()->realTimeGC())
931
{
932
TR_ASSERT(0, "genHeapAlloc() not supported for RT");
933
return;
934
}
935
936
TR::Register *metaReg = cg->getMethodMetaDataRegister();
937
uint32_t base, rotate;
938
bool sizeInReg = (isVariableLen || !constantIsImmed8r(allocSize, &base, &rotate));
939
940
TR::ILOpCodes opCode = node->getOpCodeValue();
941
bool isArrayAlloc = (opCode == TR::newarray || opCode == TR::anewarray);
942
943
if (isVariableLen)
944
{
945
// This is coming from the cg setting: less than 0x10000000 will not wrap around
946
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::and_r, node, zeroReg, enumReg, 0x000000FF, 24, iCursor);
947
iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, callLabel, iCursor);
948
949
if (isArrayAlloc)
950
{
951
// Zero length arrays are discontiguous
952
iCursor = generateSrc2Instruction(cg, TR::InstOpCode::tst, node, enumReg, enumReg, iCursor);
953
iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, callLabel, iCursor);
954
}
955
}
956
957
TR::MemoryReference *tempMR;
958
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, heapAlloc), cg);
959
iCursor = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, resReg, tempMR, iCursor);
960
//tempMR = new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, heapTop), cg);
961
//iCursor = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, heapTopReg, tempMR, iCursor);
962
963
if (sizeInReg)
964
{
965
if (isVariableLen)
966
{
967
int32_t elementSize = TR::Compiler->om.getSizeOfArrayElement(node);
968
int32_t round = (elementSize >= OBJECT_ALIGNMENT) ? 0 : OBJECT_ALIGNMENT; // zero indicates no rounding is necessary
969
bool headerAligned = allocSize % OBJECT_ALIGNMENT ? 0 : 1;
970
971
if (elementSize >= 4)
972
{
973
TR_ARMOperand2 *operand2 = new (cg->trHeapMemory()) TR_ARMOperand2(ARMOp2RegLSLImmed, enumReg, trailingZeroes(elementSize));
974
iCursor = generateTrg1Src1Instruction(cg, TR::InstOpCode::mov, node, dataSizeReg, operand2, iCursor);
975
}
976
else
977
{
978
// Round the data area to a multiple of 4
979
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, dataSizeReg, enumReg, 3, 0, iCursor);
980
if (elementSize == 2)
981
{
982
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, dataSizeReg, dataSizeReg, enumReg, iCursor);
983
}
984
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::bic, node, dataSizeReg, dataSizeReg, 3, 0, iCursor);
985
}
986
if ((round != 0 && round != 4) || !headerAligned)
987
{
988
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, sizeReg, dataSizeReg, allocSize+round-1, 0, iCursor);
989
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::bic, node, sizeReg, sizeReg, round-1, 0, iCursor);
990
}
991
else
992
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, sizeReg, dataSizeReg, allocSize, 0, iCursor);
993
}
994
else
995
iCursor = armLoadConstant(node, allocSize, sizeReg, cg, iCursor);
996
}
997
998
// Borrowing heapTopReg
999
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, heapTop), cg);
1000
iCursor = generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, heapTopReg, tempMR, iCursor);
1001
1002
// Calculate the after-allocation heapAlloc: if the size is huge,
1003
// we need to check address wrap-around also. This is unsigned
1004
// integer arithmetic, checking carry bit is enough to detect it.
1005
// For variable length array, we did an up-front check already.
1006
1007
if (allocSize > cg->getMaxObjectSizeGuaranteedNotToOverflow())
1008
{
1009
if (sizeInReg)
1010
{
1011
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add_r, node, sizeReg, resReg, sizeReg, iCursor);
1012
}
1013
else
1014
{
1015
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add_r, node, sizeReg, resReg, base, rotate, iCursor);
1016
}
1017
iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeCS, callLabel, iCursor);
1018
}
1019
else
1020
{
1021
if (sizeInReg)
1022
{
1023
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, sizeReg, resReg, sizeReg, iCursor);
1024
}
1025
else
1026
{
1027
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, sizeReg, resReg, base, rotate, iCursor);
1028
}
1029
}
1030
1031
iCursor = generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, sizeReg, heapTopReg, iCursor);
1032
iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeHI, callLabel, iCursor);
1033
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, heapAlloc), cg);
1034
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, sizeReg, iCursor);
1035
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, zeroReg, 0, 0, iCursor);
1036
}
1037
1038
1039
static void genInitObjectHeader(TR::CodeGenerator *cg,
1040
TR::Node *node,
1041
TR::Instruction * &iCursor,
1042
J9Class *clazz,
1043
TR::Register *classReg,
1044
TR::Register *resReg,
1045
TR::Register *zeroReg,
1046
TR::Register *temp1Reg,
1047
TR::Register *temp2Reg)
1048
{
1049
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
1050
uint32_t staticFlag = clazz->romClass->instanceShape;
1051
TR::Register *metaReg = cg->getMethodMetaDataRegister();
1052
TR::MemoryReference *tempMR;
1053
1054
// Store the class
1055
if (classReg == NULL)
1056
{
1057
iCursor = armLoadConstant(node, (int32_t)clazz, temp1Reg, cg, iCursor);
1058
1059
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(resReg, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), cg);
1060
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, temp1Reg, iCursor);
1061
}
1062
else
1063
{
1064
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(resReg, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), cg);
1065
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, classReg, iCursor);
1066
}
1067
1068
// If the object flags cannot be determined at compile time, we have to add a load
1069
// for it. And then, OR it with temp1Reg.
1070
// todo: if MODRON_GC is used, staticFlag could be obtained dynamically, and using isStaticObjectFlags and
1071
// getStaticObjectFlags interfaces
1072
1073
#ifndef J9VM_INTERP_FLAGS_IN_CLASS_SLOT
1074
bool isStaticFlag = fej9->isStaticObjectFlags();
1075
1076
#if defined(J9VM_OPT_NEW_OBJECT_HASH)
1077
// TODO: need to handle the !isStaticFlag case as mentioned above.
1078
// TODO: only one temp register is needed. Fix later
1079
if (isStaticFlag != 0)
1080
{
1081
staticFlag |= fej9->getStaticObjectFlags();
1082
iCursor = armLoadConstant(node, staticFlag, temp1Reg, cg, iCursor);
1083
}
1084
#else
1085
1086
// Calculate: (resReg << 14) & 0x7FFF0000
1087
// I can only think of 4 instructions sequence which takes advantage of the fact
1088
// that resReg itself is at least dword-aligned. Need to revisit whether there is
1089
// better sequence.
1090
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, temp1Reg, 2, 16, iCursor);
1091
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::sub, node, temp1Reg, temp1Reg, 1, 0, iCursor);
1092
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::and_, node, temp1Reg, resReg, temp1Reg, iCursor);
1093
iCursor = generateTrg1Src1Instruction(cg, TR::InstOpCode::mov, node, temp1Reg,
1094
new (cg->trHeapMemory()) TR_ARMOperand2(ARMOp2RegLSLImmed, temp1Reg, 14), iCursor);
1095
1096
if (isStaticFlag != 0)
1097
{
1098
staticFlag |= fej9->getStaticObjectFlags();
1099
uint32_t val1, val2;
1100
if (constantIsImmed8r(staticFlag, &val1, &val2))
1101
{
1102
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::orr, node, temp1Reg, temp1Reg, val1, val2, iCursor);
1103
}
1104
else
1105
{
1106
iCursor = armLoadConstant(node, staticFlag, temp2Reg, cg, iCursor);
1107
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::orr, node, temp1Reg, temp1Reg, temp2Reg, iCursor);
1108
}
1109
}
1110
#endif /* J9VM_OPT_NEW_OBJECT_HASH */
1111
1112
// Store the flags
1113
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(resReg, (int32_t)TR::Compiler->om.offsetOfHeaderFlags(), cg);
1114
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, temp1Reg, iCursor);
1115
#endif /* J9VM_INTERP_FLAGS_IN_CLASS_SLOT */
1116
}
1117
1118
1119
static void genAlignDoubleArray(TR::CodeGenerator *cg,
1120
TR::Node *node,
1121
TR::Instruction *&iCursor,
1122
bool isVariableLen,
1123
TR::Register *resReg,
1124
int32_t objectSize,
1125
int32_t dataBegin,
1126
TR::Register *dataSizeReg,
1127
TR::Register *temp1Reg,
1128
TR::Register *temp2Reg)
1129
{
1130
TR::LabelSymbol *slotAtStart = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
1131
TR::LabelSymbol *doneAlign = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
1132
1133
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::and_r, node, temp1Reg, resReg, 7, 0, iCursor);
1134
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, temp2Reg, 3, 0, iCursor);
1135
iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, slotAtStart, iCursor);
1136
1137
// Should be able to have branch-less sequence here ... but we need to change armLoadConstant for that.
1138
// TODO: consider this for the future.
1139
1140
// The slop bytes are at the end of the allocated object.
1141
TR::MemoryReference *tempMR;
1142
if (isVariableLen)
1143
{
1144
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(temp1Reg, dataBegin, cg);
1145
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp1Reg, resReg, dataSizeReg, iCursor);
1146
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, temp2Reg, iCursor);
1147
}
1148
else if (objectSize > UPPER_IMMED12)
1149
{
1150
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(resReg, temp1Reg, cg);
1151
iCursor = armLoadConstant(node, objectSize, temp1Reg, cg, iCursor);
1152
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, temp2Reg, iCursor);
1153
}
1154
else
1155
{
1156
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(resReg, objectSize, cg);
1157
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, temp2Reg, iCursor);
1158
}
1159
iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, doneAlign, iCursor);
1160
1161
// the slop bytes are at the start of the allocation
1162
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(resReg, (int32_t)0, cg);
1163
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, slotAtStart, iCursor);
1164
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, temp2Reg, iCursor);
1165
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, resReg, resReg, 4, 0, iCursor);
1166
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, doneAlign, iCursor);
1167
}
1168
1169
1170
static void genInitArrayHeader(TR::CodeGenerator *cg,
1171
TR::Node *node,
1172
TR::Instruction *&iCursor,
1173
bool isVariableLen,
1174
J9Class *clazz,
1175
TR::Register *resReg,
1176
TR::Register *zeroReg,
1177
TR::Register *eNumReg,
1178
TR::Register *dataSizeReg,
1179
TR::Register *temp1Reg,
1180
TR::Register *temp2Reg)
1181
{
1182
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
1183
int32_t elementSize = TR::Compiler->om.getSizeOfArrayElement(node);
1184
TR::Register *instanceSizeReg;
1185
1186
genInitObjectHeader(cg, node, iCursor, clazz, NULL, resReg, zeroReg, temp1Reg, temp2Reg);
1187
1188
instanceSizeReg = eNumReg;
1189
1190
// Store the array size
1191
TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(resReg, (int32_t)(fej9->getOffsetOfContiguousArraySizeField()), cg);
1192
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, instanceSizeReg, iCursor);
1193
}
1194
1195
1196
TR::Register *OMR::ARM::TreeEvaluator::VMnewEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1197
{
1198
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
1199
int32_t dataBegin, idx;
1200
J9Class *clazz;
1201
TR::Register *callResult;
1202
TR::LabelSymbol *callLabel, *doneLabel;
1203
TR::RegisterDependencyConditions *deps;
1204
TR::Instruction *iCursor = NULL;
1205
bool isArray = false, isDoubleArray = false;
1206
TR::Compilation *comp = TR::comp();
1207
1208
// AOT does not support inline allocates - cannot currently guarantee totalInstanceSize
1209
1210
// If the helper symbol set on the node is TR_newValue, we are (expecting to be)
1211
// dealing with a value type. Since we do not fully support value types yet, always
1212
// call the JIT helper to do the allocation.
1213
1214
TR::ILOpCodes opCode = node->getOpCodeValue();
1215
int32_t objectSize = cg->comp()->canAllocateInlineOnStack(node, (TR_OpaqueClassBlock *&) clazz);
1216
bool isVariableLen = (objectSize == 0);
1217
if (objectSize < 0 || comp->compileRelocatableCode() || comp->suppressAllocationInlining() ||
1218
TR::TreeEvaluator::requireHelperCallValueTypeAllocation(node, cg))
1219
{
1220
TR::Node::recreate(node, TR::acall);
1221
callResult = directCallEvaluator(node, cg);
1222
TR::Node::recreate(node, opCode);
1223
return callResult;
1224
}
1225
1226
TR::Register *enumReg;
1227
TR::Register *classReg;
1228
int32_t allocateSize = objectSize;
1229
callLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
1230
doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
1231
deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(10, 10, cg->trMemory());
1232
1233
TR::Node *firstChild = node->getFirstChild();
1234
TR::Node *secondChild = NULL;
1235
1236
if (opCode == TR::New)
1237
{
1238
classReg = cg->evaluate(firstChild);
1239
if (firstChild->getReferenceCount() > 1)
1240
{
1241
TR::Register *copyReg = cg->allocateRegister();
1242
iCursor = generateTrg1Src1Instruction(cg, TR::InstOpCode::mov, node, copyReg, classReg, iCursor);
1243
classReg = copyReg;
1244
}
1245
dataBegin = TR::Compiler->om.objectHeaderSizeInBytes();
1246
}
1247
else
1248
{
1249
isArray = true;
1250
dataBegin = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();
1251
secondChild = node->getSecondChild();
1252
#ifndef J9VM_GC_ALIGN_OBJECTS
1253
if (opCode == TR::newarray)
1254
{
1255
if (secondChild->getInt() == 7 || secondChild->getInt() == 11)
1256
{
1257
// To ensure 8-byte alignment on the array, we need 4-byte slop.
1258
allocateSize += 4;
1259
isDoubleArray = true;
1260
}
1261
}
1262
else
1263
{
1264
TR_ASSERT(opCode == TR::anewarray, "Bad opCode for VMnewEvaluator");
1265
}
1266
#endif
1267
// Potential helper call requires us to evaluate the arguments always.
1268
// For TR::newarray, classReg refers to the primitive type, not a class.
1269
enumReg = cg->evaluate(firstChild);
1270
classReg = cg->evaluate(secondChild);
1271
if (secondChild->getReferenceCount() > 1)
1272
{
1273
TR::Register *copyReg = cg->allocateRegister();
1274
iCursor = generateTrg1Src1Instruction(cg, TR::InstOpCode::mov, node, copyReg, classReg, iCursor);
1275
classReg = copyReg;
1276
}
1277
}
1278
1279
TR::addDependency(deps, classReg, TR::RealRegister::NoReg, TR_GPR, cg);
1280
if (secondChild == NULL)
1281
enumReg = cg->allocateRegister();
1282
TR::addDependency(deps, enumReg, TR::RealRegister::NoReg, TR_GPR, cg);
1283
1284
// We have two paths through this code, each of which calls a different helper:
1285
// one calls jitNewObject, the other performs a write barrier (when multimidlets are enabled).
1286
// Each helper has different register allocation requirements so we'll set the deps here for
1287
// the write barrier (which should be the common case), and fix up the registers in the call
1288
// to jitNewObject.
1289
1290
TR::Register *resReg = cg->allocateRegister();
1291
TR::Register *zeroReg = cg->allocateRegister();
1292
TR::Register *dataSizeReg = cg->allocateRegister();
1293
TR::Register *temp1Reg = cg->allocateRegister();
1294
TR::Register *temp2Reg = cg->allocateRegister();
1295
TR::addDependency(deps, resReg, TR::RealRegister::gr0, TR_GPR, cg);
1296
TR::addDependency(deps, zeroReg, TR::RealRegister::NoReg, TR_GPR, cg);
1297
TR::addDependency(deps, dataSizeReg, TR::RealRegister::NoReg, TR_GPR, cg);
1298
TR::addDependency(deps, temp1Reg, TR::RealRegister::gr2, TR_GPR, cg);
1299
TR::addDependency(deps, temp2Reg, TR::RealRegister::gr1, TR_GPR, cg);
1300
1301
1302
if (isVariableLen)
1303
allocateSize += dataBegin;
1304
else
1305
allocateSize = (allocateSize + OBJECT_ALIGNMENT - 1) & (-OBJECT_ALIGNMENT);
1306
1307
// classReg and enumReg have to be intact still, in case we have to call the helper.
1308
// On return, zeroReg is set to 0, and dataSizeReg is set to the size of data area if
1309
// isVariableLen is true.
1310
genHeapAlloc(cg, node, iCursor, isVariableLen, enumReg, resReg, zeroReg, dataSizeReg, temp1Reg, temp2Reg, callLabel, allocateSize);
1311
1312
if (isArray)
1313
{
1314
// Align the array if necessary.
1315
if (isDoubleArray)
1316
genAlignDoubleArray(cg, node, iCursor, isVariableLen, resReg, objectSize, dataBegin, dataSizeReg, temp1Reg, temp2Reg);
1317
genInitArrayHeader(cg, node, iCursor, isVariableLen, clazz, resReg, zeroReg, enumReg, dataSizeReg, temp1Reg, temp2Reg);
1318
}
1319
else
1320
{
1321
genInitObjectHeader(cg, node, iCursor, clazz, classReg, resReg, zeroReg, temp1Reg, temp2Reg);
1322
}
1323
1324
// Perform initialization if it is needed:
1325
// 1) Initialize certain array elements individually. This depends on the optimizer
1326
// providing a "short" list of individual indices;
1327
// 2) Initialize the whole array:
1328
// a) If the object size is constant, we can choose strategy depending on the
1329
// size of the array. Using straight line of code, or unrolled loop;
1330
// b) For variable length of array, do a counted loop;
1331
1332
TR_ExtraInfoForNew *initInfo = node->getSymbolReference()->getExtraInfo();
1333
TR::MemoryReference *tempMR;
1334
1335
if (!node->canSkipZeroInitialization() && (initInfo == NULL || initInfo->numZeroInitSlots > 0))
1336
{
1337
if (!isVariableLen)
1338
{
1339
if (initInfo!=NULL && initInfo->zeroInitSlots!=NULL &&
1340
initInfo->numZeroInitSlots<=9 && objectSize<=UPPER_IMMED12)
1341
{
1342
TR_BitVectorIterator bvi(*initInfo->zeroInitSlots);
1343
1344
while (bvi.hasMoreElements())
1345
{
1346
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(resReg, bvi.getNextElement() * 4 + dataBegin, cg);
1347
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, zeroReg, iCursor);
1348
}
1349
}
1350
else if (objectSize > 48)
1351
{
1352
// maybe worth of exploring the possibility of using dcbz, but the alignment
1353
// would require a little more cost of setup.
1354
1355
int32_t loopCnt = (objectSize - dataBegin) >> 4;
1356
int32_t residue = ((objectSize - dataBegin) >> 2) & 0x03;
1357
TR::LabelSymbol *initLoop = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
1358
1359
iCursor = armLoadConstant(node, loopCnt, temp1Reg, cg, iCursor);
1360
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, temp2Reg, resReg, dataBegin, 0, iCursor);
1361
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, initLoop, iCursor);
1362
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(temp2Reg, 0, cg);
1363
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, zeroReg, iCursor);
1364
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(temp2Reg, 4, cg);
1365
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, zeroReg, iCursor);
1366
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(temp2Reg, 8, cg);
1367
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, zeroReg, iCursor);
1368
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(temp2Reg, 12, cg);
1369
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, zeroReg, iCursor);
1370
1371
// TODO: add the update form instruction, we will not need the following instruction
1372
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, temp2Reg, temp2Reg, 16, 0, iCursor);
1373
1374
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::sub_r, node, temp1Reg, temp1Reg, 1, 0, iCursor);
1375
iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, initLoop, iCursor);
1376
for (idx = 0; idx < residue; idx++)
1377
{
1378
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(temp2Reg, idx << 2, cg);
1379
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, zeroReg, iCursor);
1380
}
1381
}
1382
else
1383
{
1384
for (idx = dataBegin; idx < objectSize; idx += 4)
1385
{
1386
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(resReg, idx, cg);
1387
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, zeroReg, iCursor);
1388
}
1389
}
1390
}
1391
else // Init variable length array
1392
{
1393
// Test for zero length array: also set up loop count
1394
1395
iCursor = generateTrg1Src1Instruction(cg, TR::InstOpCode::mov_r, node, temp1Reg, new (cg->trHeapMemory()) TR_ARMOperand2(ARMOp2RegLSRImmed, dataSizeReg, 2), iCursor);
1396
iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, doneLabel, iCursor);
1397
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, temp2Reg, resReg, dataBegin - 4, 0, iCursor);
1398
1399
TR::LabelSymbol *initLoop = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
1400
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, initLoop, iCursor);
1401
tempMR = new (cg->trHeapMemory()) TR::MemoryReference(temp2Reg, temp1Reg, 4, cg);
1402
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, zeroReg, iCursor);
1403
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::sub_r, node, temp1Reg, temp1Reg, 1, 0, iCursor);
1404
iCursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, initLoop, iCursor);
1405
}
1406
}
1407
generateConditionalBranchInstruction(cg, node, ARMConditionCodeAL, doneLabel);
1408
1409
// TODO: using snippet to better use of branch prediction facility
1410
generateLabelInstruction(cg, TR::InstOpCode::label, node, callLabel);
1411
generateTrg1Src1Instruction(cg, TR::InstOpCode::mov, node, resReg, classReg);
1412
if (secondChild != NULL)
1413
generateTrg1Src1Instruction(cg, TR::InstOpCode::mov, node, temp2Reg, enumReg);
1414
iCursor = generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uint32_t)node->getSymbolReference()->getMethodAddress(), deps, node->getSymbolReference());
1415
iCursor->ARMNeedsGCMap(0xFFFFFFFE); // mask off gr0
1416
cg->machine()->setLinkRegisterKilled(true);
1417
generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, deps);
1418
deps->stopAddingConditions();
1419
1420
cg->decReferenceCount(firstChild);
1421
if (secondChild != NULL)
1422
cg->decReferenceCount(secondChild);
1423
1424
node->setRegister(resReg);
1425
resReg->setContainsCollectedReference();
1426
return resReg;
1427
}
1428
1429
TR::Register *
1430
OMR::ARM::TreeEvaluator::VMmonentEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1431
{
1432
TR::Compilation *comp = TR::comp();
1433
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
1434
int32_t lwOffset = fej9->getByteOffsetToLockword(cg->getMonClass(node));
1435
1436
if ((comp->getOption(TR_FullSpeedDebug) /*&& !comp->getOption(TR_EnableLiveMonitorMetadata)*/) ||
1437
comp->getOption(TR_DisableInlineMonEnt) ||
1438
lwOffset <= 0)
1439
{
1440
TR::ILOpCodes opCode = node->getOpCodeValue();
1441
TR::Node::recreate(node, TR::call);
1442
TR::Register *targetRegister = directCallEvaluator(node, cg);
1443
TR::Node::recreate(node, opCode);
1444
return targetRegister;
1445
}
1446
1447
TR::Node *objNode = node->getFirstChild();
1448
TR::Register *objReg = cg->evaluate(objNode);
1449
TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(4, 4, cg->trMemory());
1450
TR::Register *metaReg, *dataReg, *addrReg;
1451
TR::LabelSymbol *callLabel;
1452
TR::Instruction *iCursor;
1453
1454
metaReg = cg->getMethodMetaDataRegister();
1455
dataReg = cg->allocateRegister();
1456
addrReg = cg->allocateRegister();
1457
TR::addDependency(deps, objReg, TR::RealRegister::gr0, TR_GPR, cg);
1458
TR::addDependency(deps, dataReg, TR::RealRegister::NoReg, TR_GPR, cg);
1459
TR::addDependency(deps, addrReg, TR::RealRegister::NoReg, TR_GPR, cg);
1460
1461
TR::Register *tempReg = cg->allocateRegister();
1462
TR::addDependency(deps, tempReg, TR::RealRegister::NoReg, TR_GPR, cg);
1463
1464
callLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
1465
1466
// This is spinning on the object itself and not on the global objectFlagSpinLock
1467
TR::LabelSymbol *incLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
1468
TR::LabelSymbol *loopLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
1469
TR::LabelSymbol *doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
1470
1471
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, addrReg, objReg, lwOffset, 0);
1472
generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);
1473
generateTrg1MemInstruction(cg, TR::InstOpCode::ldrex, node, dataReg, new (cg->trHeapMemory()) TR::MemoryReference(addrReg, (int32_t)0, cg));
1474
generateSrc1ImmInstruction(cg, TR::InstOpCode::cmp, node, dataReg, 0, 0);
1475
TR::Instruction *cursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, incLabel);
1476
1477
generateTrg1MemSrc1Instruction(cg, TR::InstOpCode::strex, node, tempReg, new (cg->trHeapMemory()) TR::MemoryReference(addrReg, (int32_t)0, cg), metaReg);
1478
generateSrc1ImmInstruction(cg, TR::InstOpCode::cmp, node, tempReg, 0, 0);
1479
generateConditionalBranchInstruction(cg, node, ARMConditionCodeNE, loopLabel);
1480
1481
if (cg->comp()->target().isSMP() && cg->comp()->target().cpu.id() != TR_DefaultARMProcessor)
1482
{
1483
generateInstruction(cg, (cg->comp()->target().cpu.id() == TR_ARMv6) ? TR::InstOpCode::dmb_v6 : TR::InstOpCode::dmb, node);
1484
}
1485
1486
generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, deps);
1487
1488
TR::Snippet *snippet = new (cg->trHeapMemory()) TR::ARMMonitorEnterSnippet(cg, node, lwOffset, incLabel, callLabel, doneLabel);
1489
cg->addSnippet(snippet);
1490
doneLabel->setEndInternalControlFlow();
1491
1492
deps->stopAddingConditions();
1493
1494
cg->decReferenceCount(objNode);
1495
return NULL;
1496
}
1497
1498
/*
1499
TR::Register *OMR::Power::TreeEvaluator::VMarrayCheckEvaluator(TR::Node *node)
1500
{
1501
TR::Register *obj1Reg, *obj2Reg, *tmp1Reg, *tmp2Reg, *cndReg;
1502
TR::LabelSymbol *doneLabel, *snippetLabel;
1503
TR_Instruction *gcPoint;
1504
TR::Snippet *snippet;
1505
TR::RegisterDependencyConditions *conditions;
1506
int32_t depIndex;
1507
1508
obj1Reg = ppcCodeGen->evaluate(node->getFirstChild());
1509
obj2Reg = ppcCodeGen->evaluate(node->getSecondChild());
1510
doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),ppcCodeGen);
1511
conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(5, 5, cg->trMemory());
1512
depIndex = 0;
1513
nonFixedDependency(conditions, obj1Reg, &depIndex, TR_GPR, true);
1514
nonFixedDependency(conditions, obj2Reg, &depIndex, TR_GPR, true);
1515
tmp1Reg = nonFixedDependency(conditions, NULL, &depIndex, TR_GPR, false);
1516
tmp2Reg = nonFixedDependency(conditions, NULL, &depIndex, TR_GPR, false);
1517
cndReg = ppcCodeGen->allocateRegister(TR_CCR);
1518
TR::addDependency(conditions, cndReg, TR::RealRegister::cr0, TR_CCR, cg);
1519
1520
// We have a unique snippet sharing arrangement in this code sequence.
1521
// It is not generally applicable for other situations.
1522
snippetLabel = NULL;
1523
1524
// Same array, we are done.
1525
//
1526
generateTrg1Src2Instruction(TR::InstOpCode::cmpl4, node, cndReg, obj1Reg, obj2Reg);
1527
generateConditionalBranchInstruction(TR::InstOpCode::beq, node, doneLabel, cndReg);
1528
1529
// If we know nothing about either object, test object1 first. It has to be an array.
1530
//
1531
if (!node->isArrayChkPrimitiveArray1() &&
1532
!node->isArrayChkReferenceArray1() &&
1533
!node->isArrayChkPrimitiveArray2() &&
1534
!node->isArrayChkReferenceArray2())
1535
{
1536
generateTrg1MemInstruction(TR::InstOpCode::lwz, node, tmp1Reg,
1537
new (cg->trHeapMemory()) TR::MemoryReference(obj1Reg, (int32_t)TR::Compiler->om.offsetOfHeaderFlags(), 4));
1538
generateTrg1Src1ImmInstruction(TR::InstOpCode::andi_r, node, tmp1Reg, tmp1Reg, OBJECT_HEADER_INDEXABLE);
1539
snippetLabel = TR::LabelSymbol::create(cg->trHeapMemory(),ppcCodeGen);
1540
gcPoint = generateConditionalBranchInstruction(TR::InstOpCode::beql, node, snippetLabel, cndReg);
1541
snippet = new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(snippetLabel, node->getSymbolReference());
1542
ppcCodeGen->addSnippet(snippet);
1543
}
1544
1545
// One of the object is array. Test equality of two objects' classes.
1546
//
1547
generateTrg1MemInstruction(TR::InstOpCode::lwz, node, tmp2Reg,
1548
new (cg->trHeapMemory()) TR::MemoryReference(obj2Reg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), 4));
1549
generateTrg1MemInstruction(TR::InstOpCode::lwz, node, tmp1Reg,
1550
new (cg->trHeapMemory()) TR::MemoryReference(obj1Reg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), 4));
1551
generateTrg1Src2Instruction(TR::InstOpCode::cmpl4, node, cndReg, tmp1Reg, tmp2Reg);
1552
1553
// If either object is known to be of primitive component type,
1554
// we are done: since both of them have to be of equal class.
1555
if (node->isArrayChkPrimitiveArray1() || node->isArrayChkPrimitiveArray2())
1556
{
1557
if (snippetLabel == NULL)
1558
{
1559
snippetLabel = TR::LabelSymbol::create(cg->trHeapMemory(),ppcCodeGen);
1560
gcPoint = generateConditionalBranchInstruction(TR::InstOpCode::bnel, node, snippetLabel, cndReg);
1561
snippet = new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(snippetLabel, node->getSymbolReference());
1562
ppcCodeGen->addSnippet(snippet);
1563
}
1564
else
1565
generateConditionalBranchInstruction(TR::InstOpCode::bne, node, snippetLabel, cndReg);
1566
}
1567
// We have to take care of the un-equal class situation: both of them must be of reference array
1568
else
1569
{
1570
generateConditionalBranchInstruction(TR::InstOpCode::beq, node, doneLabel, cndReg);
1571
1572
// Object1 must be of reference component type, otherwise throw exception
1573
if (!node->isArrayChkReferenceArray1())
1574
{
1575
generateTrg1MemInstruction(TR::InstOpCode::lwz, node, tmp1Reg,
1576
new (cg->trHeapMemory()) TR::MemoryReference(obj1Reg, (int32_t)TR::Compiler->om.offsetOfHeaderFlags(), 4));
1577
generateTrg1Src1ImmInstruction(TR::InstOpCode::andi_r, node, tmp1Reg, tmp1Reg, OBJECT_HEADER_SHAPE_MASK);
1578
if (snippetLabel == NULL)
1579
{
1580
snippetLabel = TR::LabelSymbol::create(cg->trHeapMemory(),ppcCodeGen);
1581
gcPoint = generateConditionalBranchInstruction(TR::InstOpCode::bnel, node, snippetLabel, cndReg);
1582
snippet = new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(snippetLabel, node->getSymbolReference());
1583
ppcCodeGen->addSnippet(snippet);
1584
}
1585
else
1586
generateConditionalBranchInstruction(TR::InstOpCode::bne, node, snippetLabel, cndReg);
1587
}
1588
1589
// Object2 must be of reference component type array, otherwise throw exception
1590
if (!node->isArrayChkReferenceArray2())
1591
{
1592
generateTrg1MemInstruction(TR::InstOpCode::lwz, node, tmp2Reg,
1593
new (cg->trHeapMemory()) TR::MemoryReference(obj2Reg, (int32_t)TR::Compiler->om.offsetOfHeaderFlags(), 4));
1594
generateTrg1Src1ImmInstruction(TR::InstOpCode::andi_r, node, tmp1Reg, tmp2Reg, OBJECT_HEADER_INDEXABLE);
1595
if (snippetLabel == NULL)
1596
{
1597
snippetLabel = TR::LabelSymbol::create(cg->trHeapMemory(),ppcCodeGen);
1598
gcPoint = generateConditionalBranchInstruction(TR::InstOpCode::beql, node, snippetLabel, cndReg);
1599
snippet = new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(snippetLabel, node->getSymbolReference());
1600
ppcCodeGen->addSnippet(snippet);
1601
}
1602
else
1603
generateConditionalBranchInstruction(TR::InstOpCode::beq, node, snippetLabel, cndReg);
1604
1605
generateTrg1Src1ImmInstruction(TR::InstOpCode::andi_r, node, tmp1Reg, tmp2Reg, OBJECT_HEADER_SHAPE_MASK);
1606
generateConditionalBranchInstruction(TR::InstOpCode::bne, node, snippetLabel, cndReg);
1607
}
1608
}
1609
1610
generateDepLabelInstruction(TR::InstOpCode::label, node, doneLabel, conditions);
1611
1612
conditions->stopUsingDepRegs(obj1Reg, obj2Reg);
1613
1614
ppcCodeGen->decReferenceCount(node->getFirstChild());
1615
ppcCodeGen->decReferenceCount(node->getSecondChild());
1616
return NULL;
1617
}
1618
1619
1620
void OMR::Power::TreeEvaluator::VMarrayStoreCHKEvaluator(TR::Node *node, TR::Register *src, TR::Register *dst, TR::Register *t1Reg, TR::Register *t2Reg, TR::Register *cndReg, TR::LabelSymbol *toWB, TR_Instruction *iPtr)
1621
{
1622
int32_t objectClass = (int32_t)getSystemClassFromClassName("java/lang/Object", 16);
1623
int32_t upper = ((objectClass>>16) + ((objectClass & 0x00008000)>>15)) & 0x0000FFFF;
1624
int32_t lower = objectClass & 0x0000FFFF;
1625
1626
iPtr = generateTrg1MemInstruction(TR::InstOpCode::lwz, node, t1Reg,
1627
new (cg->trHeapMemory()) TR::MemoryReference(dst, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), 4), iPtr);
1628
iPtr = generateTrg1MemInstruction(TR::InstOpCode::lwz, node, t2Reg,
1629
new (cg->trHeapMemory()) TR::MemoryReference(src, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), 4), iPtr);
1630
iPtr = generateTrg1MemInstruction(TR::InstOpCode::lwz, node, t1Reg,
1631
new (cg->trHeapMemory()) TR::MemoryReference(t1Reg, (int32_t)offsetof(J9ArrayClass, componentType), 4),
1632
iPtr);
1633
iPtr = generateTrg1Src2Instruction(TR::InstOpCode::cmpl4, node, cndReg, t1Reg, t2Reg, iPtr);
1634
iPtr = generateConditionalBranchInstruction(TR::InstOpCode::beq, node, toWB, cndReg, iPtr);
1635
if (upper == 0)
1636
{
1637
iPtr = generateTrg1ImmInstruction(TR::InstOpCode::li, node, t2Reg, lower, iPtr);
1638
}
1639
else
1640
{
1641
iPtr = generateTrg1ImmInstruction(TR::InstOpCode::lis, node, t2Reg, upper, iPtr);
1642
if (lower != 0)
1643
{
1644
iPtr = generateTrg1Src1ImmInstruction(TR::InstOpCode::addi, node, t2Reg, t2Reg, lower, iPtr);
1645
}
1646
}
1647
iPtr = generateTrg1Src2Instruction(TR::InstOpCode::cmpl4, node, cndReg, t1Reg, t2Reg, iPtr);
1648
iPtr = generateConditionalBranchInstruction(TR::InstOpCode::beq, node, toWB, cndReg, iPtr);
1649
}
1650
*/
1651
1652
1653
void OMR::ARM::TreeEvaluator::VMwrtbarEvaluator(TR::Node *node, TR::Register *srcReg, TR::Register *dstReg, TR::Register *flagReg, bool needDeps, TR::CodeGenerator *cg)
1654
{
1655
TR::Compilation *comp = TR::comp();
1656
TR::LabelSymbol *doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
1657
TR::SymbolReference *wbref = comp->getSymRefTab()->findOrCreateWriteBarrierStoreSymbolRef(comp->getMethodSymbol());
1658
auto gcMode = TR::Compiler->om.writeBarrierType();
1659
1660
TR::Register *tempReg = NULL;
1661
TR::RegisterDependencyConditions *deps = NULL;
1662
1663
if (flagReg == NULL)
1664
tempReg = cg->allocateRegister();
1665
else
1666
tempReg = flagReg;
1667
1668
if (needDeps)
1669
{
1670
deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(3, 3, cg->trMemory());
1671
TR::addDependency(deps, srcReg, TR::RealRegister::gr1, TR_GPR, cg);
1672
TR::addDependency(deps, dstReg, TR::RealRegister::gr0, TR_GPR, cg);
1673
TR::addDependency(deps, tempReg, TR::RealRegister::gr2, TR_GPR, cg);
1674
}
1675
1676
// todo check for _isSourceNonNull in PPC gen to see possible opt?
1677
// nullcheck store - skip write barrier if null being written in
1678
generateSrc2Instruction(cg, TR::InstOpCode::tst, node, srcReg, srcReg);
1679
generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, doneLabel);
1680
1681
if (gcMode != gc_modron_wrtbar_always)
1682
{
1683
// check to see if colour bits give hint (read FLAGS field of J9Object).
1684
// @@ getWordOffsetToGCFlags() and getWriteBarrierGCFlagMaskAsByte() are missing in TR_FrontEnd
1685
// @@ if (flagReg == NULL)
1686
// @@ generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, tempReg, new (cg->trHeapMemory()) TR::MemoryReference(dstReg, fej9->getWordOffsetToGCFlags(), cg));
1687
// @@ generateTrg1Src2Instruction(cg, TR::InstOpCode::and_r, node, tempReg, tempReg, new (cg->trHeapMemory()) TR_ARMOperand2(fej9->getWriteBarrierGCFlagMaskAsByte(), 8));
1688
}
1689
1690
TR::Instruction *cursor = generateImmSymInstruction(cg, TR::InstOpCode::bl,
1691
node, (uintptr_t)wbref->getMethodAddress(),
1692
new (cg->trHeapMemory()) TR::RegisterDependencyConditions((uint8_t)0, 0, cg->trMemory()),
1693
wbref, NULL);
1694
1695
if (gcMode != gc_modron_wrtbar_always)
1696
{
1697
// conditional call to the write barrier
1698
cursor->setConditionCode(ARMConditionCodeNE);
1699
}
1700
1701
// place label that marks work was done.
1702
generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, deps);
1703
1704
if (flagReg == NULL)
1705
cg->stopUsingRegister(tempReg);
1706
}
1707
1708
void VMgenerateCatchBlockBBStartPrologue(TR::Node *node, TR::Instruction *fenceInstruction, TR::CodeGenerator *cg)
1709
{
1710
/* @@ not implemented @@ */
1711
}
1712
1713