Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/p/codegen/J9TreeEvaluator.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 <limits.h>
24
#include <math.h>
25
#include <stdint.h>
26
#include "j9.h"
27
#include "j9cfg.h"
28
#include "j9consts.h"
29
#include "omrmodroncore.h"
30
#include "thrdsup.h"
31
#include "thrtypes.h"
32
#include "codegen/AheadOfTimeCompile.hpp"
33
#include "codegen/BackingStore.hpp"
34
#include "codegen/CodeGenerator.hpp"
35
#include "codegen/CodeGeneratorUtils.hpp"
36
#include "codegen/CodeGenerator_inlines.hpp"
37
#include "codegen/Machine.hpp"
38
#include "codegen/Linkage.hpp"
39
#include "codegen/Linkage_inlines.hpp"
40
#include "codegen/LiveRegister.hpp"
41
#include "codegen/PPCJNILinkage.hpp"
42
#include "codegen/PPCPrivateLinkage.hpp"
43
#include "codegen/Relocation.hpp"
44
#include "codegen/Snippet.hpp"
45
#include "codegen/TreeEvaluator.hpp"
46
#include "compile/ResolvedMethod.hpp"
47
#include "control/Recompilation.hpp"
48
#include "control/RecompilationInfo.hpp"
49
#include "codegen/J9PPCWatchedInstanceFieldSnippet.hpp"
50
#include "codegen/J9PPCWatchedStaticFieldSnippet.hpp"
51
#include "env/CHTable.hpp"
52
#include "env/CompilerEnv.hpp"
53
#include "env/IO.hpp"
54
#include "env/jittypes.h"
55
#include "env/VMJ9.h"
56
#include "il/DataTypes.hpp"
57
#include "il/LabelSymbol.hpp"
58
#include "il/Node.hpp"
59
#include "il/Node_inlines.hpp"
60
#include "il/TreeTop.hpp"
61
#include "il/TreeTop_inlines.hpp"
62
#include "infra/Annotations.hpp"
63
#include "infra/Bit.hpp"
64
#include "optimizer/VectorAPIExpansion.hpp"
65
#include "p/codegen/ForceRecompilationSnippet.hpp"
66
#include "p/codegen/GenerateInstructions.hpp"
67
#include "p/codegen/InterfaceCastSnippet.hpp"
68
#include "p/codegen/J9PPCSnippet.hpp"
69
#include "p/codegen/LoadStoreHandler.hpp"
70
//#include "p/codegen/PPCAheadOfTimeCompile.hpp"
71
#include "p/codegen/PPCEvaluator.hpp"
72
#include "p/codegen/PPCInstruction.hpp"
73
#include "p/codegen/PPCTableOfConstants.hpp"
74
#include "runtime/CodeCache.hpp"
75
#include "runtime/Runtime.hpp"
76
#include "env/VMJ9.h"
77
78
#define MAX_PPC_ARRAYCOPY_INLINE 256
79
#define AIX_NULL_ZERO_AREA_SIZE 256
80
#define NUM_PICS 3
81
82
#define LOCK_INC_DEC_VALUE OBJECT_HEADER_LOCK_FIRST_RECURSION_BIT
83
#define LOCK_RESERVATION_BIT OBJECT_HEADER_LOCK_RESERVED
84
85
#define LOCK_RES_PRIMITIVE_ENTER_MASK (OBJECT_HEADER_LOCK_RECURSION_MASK | OBJECT_HEADER_LOCK_FLC)
86
#define LOCK_RES_PRIMITIVE_EXIT_MASK (OBJECT_HEADER_LOCK_BITS_MASK & ~OBJECT_HEADER_LOCK_RECURSION_MASK)
87
#define LOCK_RES_NON_PRIMITIVE_ENTER_MASK (OBJECT_HEADER_LOCK_RECURSION_MASK & ~OBJECT_HEADER_LOCK_LAST_RECURSION_BIT)
88
#define LOCK_RES_NON_PRIMITIVE_EXIT_MASK (OBJECT_HEADER_LOCK_RECURSION_MASK & ~OBJECT_HEADER_LOCK_FIRST_RECURSION_BIT)
89
90
#define LOCK_RES_OWNING_COMPLEMENT (OBJECT_HEADER_LOCK_RECURSION_MASK | OBJECT_HEADER_LOCK_FLC)
91
92
#define LOCK_NON_PRIMITIVE_ENTER_IGNORE_MASK ((OBJECT_HEADER_LOCK_RECURSION_MASK & ~OBJECT_HEADER_LOCK_LAST_RECURSION_BIT) | OBJECT_HEADER_LOCK_RESERVED | OBJECT_HEADER_LOCK_FLC)
93
#define LOCK_NON_PRIMITIVE_EXIT_IGNORE_MASK (OBJECT_HEADER_LOCK_RECURSION_MASK | OBJECT_HEADER_LOCK_RESERVED | OBJECT_HEADER_LOCK_FLC)
94
95
extern TR::Register *addConstantToLong(TR::Node * node, TR::Register *srcReg, int64_t value, TR::Register *trgReg, TR::CodeGenerator *cg);
96
extern TR::Register *addConstantToInteger(TR::Node * node, TR::Register *trgReg, TR::Register *srcReg, int32_t value, TR::CodeGenerator *cg);
97
98
static TR::InstOpCode::Mnemonic getLoadOrStoreFromDataType(TR::CodeGenerator *cg, TR::DataType dt, int32_t elementSize, bool isUnsigned, bool returnLoad);
99
void loadFieldWatchSnippet(TR::CodeGenerator *cg, TR::Node *node, TR::Snippet *dataSnippet, TR::Register *snippetReg, TR::Register *scratchReg, bool isInstance);
100
static const char *ppcSupportsReadMonitors = feGetEnv("TR_ppcSupportReadMonitors");
101
102
extern uint32_t getPPCCacheLineSize();
103
104
static TR::RegisterDependencyConditions *createConditionsAndPopulateVSXDeps(TR::CodeGenerator *cg, int32_t nonVSXDepsCount)
105
{
106
TR::RegisterDependencyConditions *conditions;
107
TR_LiveRegisters *lrVector = cg->getLiveRegisters(TR_VSX_VECTOR);
108
bool liveVSXVectorReg = (!lrVector || (lrVector->getNumberOfLiveRegisters() > 0));
109
const TR::PPCLinkageProperties& properties = cg->getLinkage()->getProperties();
110
if (liveVSXVectorReg)
111
{
112
int32_t depsCount = 64 + nonVSXDepsCount;
113
conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(depsCount, depsCount, cg->trMemory());
114
for (int32_t i = TR::RealRegister::FirstFPR; i <= TR::RealRegister::LastFPR; i++)
115
{
116
if (!properties.getPreserved((TR::RealRegister::RegNum) i))
117
{
118
TR::addDependency(conditions, NULL, (TR::RealRegister::RegNum) i, TR_FPR, cg);
119
}
120
}
121
for (int32_t i = TR::RealRegister::FirstVRF; i <= TR::RealRegister::LastVRF; i++)
122
{
123
if (!properties.getPreserved((TR::RealRegister::RegNum) i))
124
{
125
TR::addDependency(conditions, NULL, (TR::RealRegister::RegNum) i, TR_VRF, cg);
126
}
127
}
128
}
129
else
130
{
131
TR_LiveRegisters *lrScalar = cg->getLiveRegisters(TR_VSX_SCALAR);
132
if (!lrScalar || (lrScalar->getNumberOfLiveRegisters() > 0))
133
{
134
int32_t depsCount = 32 + nonVSXDepsCount;
135
conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(depsCount, depsCount, cg->trMemory());
136
for (int32_t i = TR::RealRegister::FirstVRF; i <= TR::RealRegister::LastVRF; i++)
137
{
138
if (!properties.getPreserved((TR::RealRegister::RegNum) i))
139
{
140
TR::addDependency(conditions, NULL, (TR::RealRegister::RegNum) i, TR_VRF, cg);
141
}
142
}
143
}
144
else
145
{
146
conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(nonVSXDepsCount, nonVSXDepsCount, cg->trMemory());
147
}
148
}
149
return conditions;
150
}
151
152
static TR::Instruction *genNullTest(TR::Node *node, TR::Register *objectReg, TR::Register *crReg, TR::CodeGenerator *cg, TR::Instruction *cursor = NULL)
153
{
154
cursor = generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, crReg, objectReg, NULLVALUE, cursor);
155
return cursor;
156
}
157
158
static inline TR::Instruction *genNullTest(TR::Node *node, TR::Register *objectReg, TR::Register *crReg, TR::Register *scratchReg, TR::Instruction *cursor, TR::CodeGenerator *cg)
159
{
160
TR::Instruction *iRet;
161
iRet = generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, crReg, objectReg, NULLVALUE, cursor);
162
return (iRet);
163
}
164
165
static void genInlineTest(TR::Node * node, TR_OpaqueClassBlock* castClassAddr, TR_OpaqueClassBlock** guessClassArray, uint8_t num_PICS, TR::Register * objClassReg,
166
TR::Register * resultReg, TR::Register * cndReg, TR::Register * scratch1Reg, TR::Register * scratch2Reg, bool checkCast, bool needsResult, TR::LabelSymbol * falseLabel,
167
TR::LabelSymbol * trueLabel, TR::LabelSymbol * doneLabel, TR::LabelSymbol * callLabel, bool testCastClassIsSuper, TR::Instruction *iCursor, TR::CodeGenerator * cg)
168
{
169
TR::Compilation * comp = cg->comp();
170
TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());
171
dumpOptDetails(comp, "inline test with %d guess classes\n", num_PICS);
172
TR_ASSERT(num_PICS != 0, "genInlineTest is called with at least 1 guess class\n");
173
174
TR::LabelSymbol *snippetLabel = generateLabelSymbol(cg);
175
176
// TODO: we pass callLabel twice in TR::PPCInterfaceCastSnippet. However, this is because the first one is used as
177
// the restart point on TR::PPCInterfaceCastSnippet, and the second as the reference to the call to the helper function
178
// this lets us have a more generic Snippet. This can be simplified later on, should it be needed.
179
//
180
TR::PPCInterfaceCastSnippet * guessCacheSnippet = new (cg->trHeapMemory()) TR::PPCInterfaceCastSnippet(cg, node, callLabel, snippetLabel, trueLabel, falseLabel, doneLabel,
181
callLabel, testCastClassIsSuper, checkCast, TR::Compiler->om.offsetOfObjectVftField(), offsetof(J9Class, castClassCache), needsResult);
182
cg->addSnippet(guessCacheSnippet);
183
184
uint8_t i;
185
bool result_bool;
186
int32_t result_value;
187
TR::LabelSymbol *result_label;
188
for (i = 0; i < num_PICS - 1; i++)
189
{
190
// Load the cached value in scratch1Reg
191
// HCR in genInlineTest for checkcast and instanceof
192
if (cg->wantToPatchClassPointer(guessClassArray[i], node))
193
{
194
iCursor = loadAddressConstantInSnippet(cg, node, (intptr_t) (guessClassArray[i]), scratch1Reg, scratch2Reg,TR::InstOpCode::Op_load, true, iCursor);
195
}
196
else if (comp->compileRelocatableCode() && comp->getOption(TR_UseSymbolValidationManager))
197
{
198
TR::StaticSymbol *sym = TR::StaticSymbol::create(comp->trHeapMemory(), TR::Address);
199
sym->setStaticAddress(guessClassArray[i]);
200
sym->setClassObject();
201
202
iCursor = loadAddressConstant(cg, true, node, (intptr_t) new (comp->trHeapMemory()) TR::SymbolReference(comp->getSymRefTab(), sym), scratch1Reg, iCursor, false, TR_ClassAddress);
203
}
204
else
205
{
206
iCursor = loadAddressConstant(cg, comp->compileRelocatableCode(), node, (intptr_t) (guessClassArray[i]), scratch1Reg, iCursor);
207
}
208
result_bool = fej9->instanceOfOrCheckCast((J9Class*) guessClassArray[i], (J9Class*) castClassAddr);
209
int32_t result_value = result_bool ? 1 : 0;
210
result_label = (falseLabel != trueLabel) ? (result_bool ? trueLabel : falseLabel) : doneLabel;
211
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, objClassReg, scratch1Reg, iCursor);
212
if (needsResult)
213
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, result_value, iCursor);
214
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, result_label, cndReg, iCursor);
215
}
216
217
// Load the cached value in scratch1Reg
218
if (cg->wantToPatchClassPointer(guessClassArray[num_PICS - 1], node))
219
{
220
iCursor = loadAddressConstantInSnippet(cg, node, (intptr_t) (guessClassArray[num_PICS - 1]), scratch1Reg, scratch2Reg,TR::InstOpCode::Op_load, true, iCursor);
221
}
222
else if (comp->compileRelocatableCode() && comp->getOption(TR_UseSymbolValidationManager))
223
{
224
TR::StaticSymbol *sym = TR::StaticSymbol::create(comp->trHeapMemory(), TR::Address);
225
sym->setStaticAddress(guessClassArray[num_PICS - 1]);
226
sym->setClassObject();
227
228
iCursor = loadAddressConstant(cg, true, node, (intptr_t) new (comp->trHeapMemory()) TR::SymbolReference(comp->getSymRefTab(), sym), scratch1Reg, iCursor, false, TR_ClassAddress);
229
}
230
else
231
{
232
iCursor = loadAddressConstant(cg, comp->compileRelocatableCode(), node, (intptr_t) (guessClassArray[num_PICS - 1]), scratch1Reg, iCursor);
233
}
234
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, objClassReg, scratch1Reg, iCursor);
235
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, snippetLabel, cndReg, iCursor);
236
result_bool = fej9->instanceOfOrCheckCast((J9Class*) guessClassArray[num_PICS - 1], (J9Class*) castClassAddr);
237
result_value = result_bool ? 1 : 0;
238
result_label = (falseLabel != trueLabel) ? (result_bool ? trueLabel : falseLabel) : doneLabel;
239
if (needsResult)
240
{
241
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, result_value, iCursor);
242
}
243
iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, result_label, iCursor);
244
return;
245
}
246
247
static TR::Register *nonFixedDependency(TR::RegisterDependencyConditions *conditions, TR::Register *nonFixedReg, int32_t *depIndex, TR_RegisterKinds kind, bool excludeGR0,
248
TR::CodeGenerator *cg)
249
{
250
int32_t index = *depIndex;
251
252
if (nonFixedReg == NULL)
253
nonFixedReg = cg->allocateRegister(kind);
254
255
TR::addDependency(conditions, nonFixedReg, TR::RealRegister::NoReg, kind, cg);
256
257
if (excludeGR0)
258
{
259
conditions->getPreConditions()->getRegisterDependency(index)->setExcludeGPR0();
260
conditions->getPostConditions()->getRegisterDependency(index)->setExcludeGPR0();
261
}
262
263
*depIndex += 1;
264
return nonFixedReg;
265
}
266
267
static void reviveResultRegister(TR::Register *realResult, TR::Register *deadRes, TR::CodeGenerator *cg)
268
{
269
TR_RegisterKinds kind = realResult->getKind();
270
TR_LiveRegisters *liveRegs = cg->getLiveRegisters(kind);
271
272
if (deadRes->isLive())
273
deadRes->getLiveRegisterInfo()->decNodeCount();
274
cg->stopUsingRegister(deadRes);
275
276
if (liveRegs != NULL)
277
{
278
liveRegs->addRegister(realResult);
279
}
280
}
281
282
static int32_t numberOfRegisterCandidate(TR::CodeGenerator *cg, TR::Node *depNode, TR_RegisterKinds kind)
283
{
284
int32_t idx, result = 0;
285
286
for (idx = 0; idx < depNode->getNumChildren(); idx++)
287
{
288
TR::Node *child = depNode->getChild(idx);
289
TR::Register *reg;
290
291
if (child->getOpCodeValue() == TR::PassThrough)
292
child = child->getFirstChild();
293
reg = child->getRegister();
294
if (reg != NULL && reg->getKind() == kind)
295
{
296
result += 1;
297
if (kind == TR_GPR && cg->comp()->target().is32Bit() && child->getType().isInt64())
298
result += 1;
299
}
300
}
301
return (result);
302
}
303
304
// ----------------------------------------------------------------------------
305
306
307
308
/*
309
* J9 PPC specific tree evaluator table overrides
310
*/
311
extern void TEMPORARY_initJ9PPCTreeEvaluatorTable(TR::CodeGenerator *cg)
312
{
313
TR_TreeEvaluatorFunctionPointer *tet = cg->getTreeEvaluatorTable();
314
315
tet[TR::awrtbar] = TR::TreeEvaluator::awrtbarEvaluator;
316
tet[TR::awrtbari] = TR::TreeEvaluator::awrtbariEvaluator;
317
tet[TR::monent] = TR::TreeEvaluator::monentEvaluator;
318
tet[TR::monexit] = TR::TreeEvaluator::monexitEvaluator;
319
tet[TR::monexitfence] = TR::TreeEvaluator::monexitfenceEvaluator;
320
tet[TR::asynccheck] = TR::TreeEvaluator::asynccheckEvaluator;
321
tet[TR::instanceof] = TR::TreeEvaluator::instanceofEvaluator;
322
tet[TR::checkcast] = TR::TreeEvaluator::checkcastEvaluator;
323
tet[TR::checkcastAndNULLCHK] = TR::TreeEvaluator::checkcastAndNULLCHKEvaluator;
324
tet[TR::New] = TR::TreeEvaluator::newObjectEvaluator;
325
tet[TR::variableNew] = TR::TreeEvaluator::newObjectEvaluator;
326
tet[TR::newarray] = TR::TreeEvaluator::newArrayEvaluator;
327
tet[TR::anewarray] = TR::TreeEvaluator::anewArrayEvaluator;
328
tet[TR::variableNewArray] = TR::TreeEvaluator::anewArrayEvaluator;
329
tet[TR::multianewarray] = TR::TreeEvaluator::multianewArrayEvaluator;
330
tet[TR::arraylength] = TR::TreeEvaluator::arraylengthEvaluator;
331
tet[TR::ResolveCHK] = TR::TreeEvaluator::resolveCHKEvaluator;
332
tet[TR::DIVCHK] = TR::TreeEvaluator::DIVCHKEvaluator;
333
tet[TR::BNDCHK] = TR::TreeEvaluator::BNDCHKEvaluator;
334
tet[TR::ArrayCopyBNDCHK] = TR::TreeEvaluator::ArrayCopyBNDCHKEvaluator;
335
tet[TR::BNDCHKwithSpineCHK] = TR::TreeEvaluator::BNDCHKwithSpineCHKEvaluator;
336
tet[TR::SpineCHK] = TR::TreeEvaluator::BNDCHKwithSpineCHKEvaluator;
337
tet[TR::ArrayStoreCHK] = TR::TreeEvaluator::ArrayStoreCHKEvaluator;
338
tet[TR::ArrayCHK] = TR::TreeEvaluator::ArrayCHKEvaluator;
339
tet[TR::MethodEnterHook] = TR::TreeEvaluator::conditionalHelperEvaluator;
340
tet[TR::MethodExitHook] = TR::TreeEvaluator::conditionalHelperEvaluator;
341
tet[TR::allocationFence] = TR::TreeEvaluator::flushEvaluator;
342
tet[TR::loadFence] = TR::TreeEvaluator::flushEvaluator;
343
tet[TR::storeFence] = TR::TreeEvaluator::flushEvaluator;
344
tet[TR::fullFence] = TR::TreeEvaluator::flushEvaluator;
345
346
tet[TR::icall] = TR::TreeEvaluator::directCallEvaluator;
347
tet[TR::lcall] = TR::TreeEvaluator::directCallEvaluator;
348
tet[TR::fcall] = TR::TreeEvaluator::directCallEvaluator;
349
tet[TR::dcall] = TR::TreeEvaluator::directCallEvaluator;
350
tet[TR::acall] = TR::TreeEvaluator::directCallEvaluator;
351
tet[TR::call] = TR::TreeEvaluator::directCallEvaluator;
352
tet[TR::vcall] = TR::TreeEvaluator::directCallEvaluator;
353
354
tet[TR::tstart] = TR::TreeEvaluator::tstartEvaluator;
355
tet[TR::tfinish] = TR::TreeEvaluator::tfinishEvaluator;
356
tet[TR::tabort] = TR::TreeEvaluator::tabortEvaluator;
357
358
tet[TR::NULLCHK] = TR::TreeEvaluator::NULLCHKEvaluator;
359
tet[TR::ResolveAndNULLCHK] = TR::TreeEvaluator::resolveAndNULLCHKEvaluator;
360
}
361
362
363
static void
364
VMoutlinedHelperWrtbarEvaluator(
365
TR::Node *node,
366
TR::Register *srcObjectReg,
367
TR::Register *dstObjectReg,
368
bool srcIsNonNull,
369
TR::CodeGenerator *cg)
370
{
371
TR::Compilation * comp = cg->comp();
372
const auto gcMode = TR::Compiler->om.writeBarrierType();
373
374
if (gcMode == gc_modron_wrtbar_none)
375
return;
376
377
const bool doWrtbar = gcMode == gc_modron_wrtbar_satb || gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always
378
|| comp->getOptions()->realTimeGC();
379
380
const bool doCardMark = !node->isNonHeapObjectWrtBar() && (gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_cardmark_incremental);
381
382
TR::CodeCache *codeCache = cg->getCodeCache();
383
TR::LabelSymbol *doneWrtbarLabel = generateLabelSymbol(cg);
384
TR::Register *srcNullCondReg;
385
386
TR_PPCScratchRegisterDependencyConditions deps;
387
388
// Clobbered by the helper
389
deps.addDependency(cg, NULL, TR::RealRegister::cr0);
390
deps.addDependency(cg, NULL, TR::RealRegister::cr1);
391
392
if (!srcIsNonNull)
393
{
394
srcNullCondReg = cg->allocateRegister(TR_CCR);
395
generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, srcNullCondReg, srcObjectReg, NULLVALUE);
396
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneWrtbarLabel, srcNullCondReg);
397
}
398
399
if (doWrtbar)
400
{
401
deps.addDependency(cg, dstObjectReg, TR::RealRegister::gr3);
402
deps.addDependency(cg, srcObjectReg, TR::RealRegister::gr4);
403
// Clobbered by the helper
404
deps.addDependency(cg, NULL, TR::RealRegister::gr5);
405
deps.addDependency(cg, NULL, TR::RealRegister::gr6);
406
deps.addDependency(cg, NULL, TR::RealRegister::gr11);
407
408
TR_CCPreLoadedCode helper = doCardMark ? TR_writeBarrierAndCardMark : TR_writeBarrier;
409
uintptr_t helperAddr = (uintptr_t) codeCache->getCCPreLoadedCodeAddress(helper, cg);
410
TR::SymbolReference *symRef = comp->getSymRefTab()->findOrCreatePerCodeCacheHelperSymbolRef(helper, helperAddr);
411
412
TR::Instruction *gcPoint = generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, helperAddr, new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 0, cg->trMemory()),
413
symRef);
414
gcPoint->PPCNeedsGCMap(0xFFFFFFFF);
415
}
416
else
417
{
418
TR_ASSERT(doCardMark, "Expecting at least one write barrier to be performed");
419
420
deps.addDependency(cg, dstObjectReg, TR::RealRegister::gr3);
421
// Clobbered by the helper
422
deps.addDependency(cg, NULL, TR::RealRegister::gr4);
423
deps.addDependency(cg, NULL, TR::RealRegister::gr5);
424
deps.addDependency(cg, NULL, TR::RealRegister::gr11);
425
426
uintptr_t helperAddr = (uintptr_t) codeCache->getCCPreLoadedCodeAddress(TR_cardMark, cg);
427
TR::SymbolReference *symRef = comp->getSymRefTab()->findOrCreatePerCodeCacheHelperSymbolRef(TR_cardMark, helperAddr);
428
generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, helperAddr, new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 0, cg->trMemory()), symRef);
429
}
430
431
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneWrtbarLabel, TR_PPCScratchRegisterDependencyConditions::createDependencyConditions(cg, NULL, &deps));
432
433
if (!srcIsNonNull)
434
cg->stopUsingRegister(srcNullCondReg);
435
436
cg->machine()->setLinkRegisterKilled(true);
437
cg->setHasCall();
438
}
439
440
TR::Register *outlinedHelperWrtbarEvaluator(TR::Node *node, TR::CodeGenerator *cg)
441
{
442
TR::Register *srcObjectReg = cg->gprClobberEvaluate(node->getFirstChild());
443
TR::Register *dstObjectReg = cg->gprClobberEvaluate(node->getSecondChild());
444
TR::Compilation* comp = cg->comp();
445
446
TR::Symbol *storeSym = node->getSymbolReference()->getSymbol();
447
const bool isOrderedShadowStore = storeSym->isShadow() && storeSym->isOrdered();
448
const bool needSync = comp->target().isSMP() && (storeSym->isSyncVolatile() || isOrderedShadowStore);
449
const bool lazyVolatile = comp->target().isSMP() && isOrderedShadowStore;
450
451
// Under real-time, store happens after the wrtbar
452
// For other GC modes, store happens before the wrtbar
453
if (comp->getOptions()->realTimeGC())
454
{
455
}
456
else
457
{
458
TR::LoadStoreHandler::generateStoreNodeSequence(cg, srcObjectReg, node, TR::InstOpCode::Op_st, TR::Compiler->om.sizeofReferenceAddress());
459
460
if (!node->getFirstChild()->isNull())
461
VMoutlinedHelperWrtbarEvaluator(node, srcObjectReg, dstObjectReg, node->getFirstChild()->isNonNull(), cg);
462
}
463
464
cg->decReferenceCount(node->getFirstChild());
465
cg->decReferenceCount(node->getSecondChild());
466
467
if (srcObjectReg != node->getFirstChild()->getRegister())
468
cg->stopUsingRegister(srcObjectReg);
469
if (dstObjectReg != node->getSecondChild()->getRegister())
470
cg->stopUsingRegister(dstObjectReg);
471
472
return NULL;
473
}
474
475
static int32_t getOffsetOfJ9ObjectFlags()
476
{
477
#if defined(J9VM_INTERP_FLAGS_IN_CLASS_SLOT)
478
#if defined(TR_TARGET_64BIT)
479
if (!TR::Compiler->om.compressObjectReferences())
480
#if defined(__LITTLE_ENDIAN__)
481
return TMP_OFFSETOF_J9OBJECT_CLAZZ;
482
#else
483
return TMP_OFFSETOF_J9OBJECT_CLAZZ + 4;
484
#endif
485
#endif
486
return TMP_OFFSETOF_J9OBJECT_CLAZZ;
487
#else
488
#if defined(TMP_OFFSETOF_J9OBJECT_FLAGS)
489
return TMP_OFFSETOF_J9OBJECT_FLAGS;
490
#else
491
return 0;
492
#endif
493
#endif
494
}
495
496
static void VMnonNullSrcWrtBarCardCheckEvaluator(TR::Node *node, TR::Register *srcReg, TR::Register *dstReg, TR::Register *condReg, TR::Register *temp1Reg, TR::Register *temp2Reg,
497
TR::Register *temp3Reg, TR::Register *temp4Reg, TR::LabelSymbol *doneLabel, TR::RegisterDependencyConditions *deps,
498
bool isCompressedRef, TR::CodeGenerator *cg, bool flagsInTemp1 = false)
499
{
500
// non-heap objects cannot be marked
501
// Make sure we really should be here
502
TR::Compilation *comp = cg->comp();
503
TR::Options *options = comp->getOptions();
504
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
505
auto gcMode = TR::Compiler->om.writeBarrierType();
506
TR::LabelSymbol *callLabel = generateLabelSymbol(cg);
507
TR::Node *wrtbarNode = NULL;
508
TR::SymbolReference *wbRef;
509
bool definitelyHeapObject = false, definitelyNonHeapObject = false;
510
bool doCrdMrk = (gcMode == gc_modron_wrtbar_cardmark_and_oldcheck);
511
bool doWrtBar = (gcMode == gc_modron_wrtbar_satb || gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always
512
|| comp->getOptions()->realTimeGC());
513
bool temp3RegIsNull = (temp3Reg == NULL);
514
515
//registers for old/new space boundaries
516
TR::Register *bound1 = cg->allocateRegister();
517
TR::Register *bound2 = cg->allocateRegister();
518
519
deps->addPostCondition(bound1, TR::RealRegister::NoReg);
520
deps->addPostCondition(bound2, TR::RealRegister::NoReg);
521
522
TR_ASSERT(doWrtBar == true, "VMnonNullSrcWrtBarCardCheckEvaluator: Invalid call to VMnonNullSrcWrtBarCardCheckEvaluator\n");
523
524
if (temp3RegIsNull)
525
{
526
temp3Reg = cg->allocateRegister();
527
TR::addDependency(deps, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);
528
}
529
530
if (node->getOpCodeValue() == TR::awrtbari || node->getOpCodeValue() == TR::awrtbar)
531
wrtbarNode = node;
532
else if (node->getOpCodeValue() == TR::ArrayStoreCHK)
533
wrtbarNode = node->getFirstChild();
534
535
if (wrtbarNode != NULL)
536
{
537
definitelyHeapObject = wrtbarNode->isHeapObjectWrtBar();
538
definitelyNonHeapObject = wrtbarNode->isNonHeapObjectWrtBar();
539
}
540
541
if (gcMode == gc_modron_wrtbar_cardmark_and_oldcheck)
542
wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierStoreGenerationalAndConcurrentMarkSymbolRef(comp->getMethodSymbol());
543
else if (gcMode == gc_modron_wrtbar_oldcheck)
544
wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierStoreGenerationalSymbolRef(comp->getMethodSymbol());
545
else if (comp->getOptions()->realTimeGC())
546
{
547
if (wrtbarNode->getOpCodeValue() == TR::awrtbar || wrtbarNode->isUnsafeStaticWrtBar())
548
wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierClassStoreRealTimeGCSymbolRef(comp->getMethodSymbol());
549
else
550
wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierStoreRealTimeGCSymbolRef(comp->getMethodSymbol());
551
}
552
else
553
wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierStoreSymbolRef(comp->getMethodSymbol());
554
555
if (gcMode != gc_modron_wrtbar_always && !comp->getOptions()->realTimeGC())
556
{
557
bool inlineCrdmrk = (doCrdMrk && !definitelyNonHeapObject);
558
// object header flags now occupy 4bytes (instead of 8) on 64-bit. Keep it in temp1Reg for following checks.
559
560
TR::Register *metaReg = cg->getMethodMetaDataRegister();
561
562
TR::LabelSymbol* startICF = generateLabelSymbol(cg);
563
startICF->setStartInternalControlFlow();
564
565
// dstReg - heapBaseForBarrierRange0
566
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, bound1,
567
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapBaseForBarrierRange0), TR::Compiler->om.sizeofReferenceAddress()));
568
generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, temp3Reg, bound1, dstReg);
569
570
// if (temp3Reg >= heapSizeForBarrierRage0), object not in the tenured area
571
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, bound2,
572
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapSizeForBarrierRange0), TR::Compiler->om.sizeofReferenceAddress()));
573
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp3Reg, bound2);
574
generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, doneLabel, condReg);
575
576
if (!flagsInTemp1)
577
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, temp1Reg, TR::MemoryReference::createWithDisplacement(cg, dstReg, getOffsetOfJ9ObjectFlags(), 4));
578
579
if (inlineCrdmrk)
580
{
581
TR::LabelSymbol *noChkLabel = NULL;
582
583
// Balanced policy must always dirty the card table.
584
//
585
if (gcMode != gc_modron_wrtbar_cardmark_incremental)
586
{
587
noChkLabel = generateLabelSymbol(cg);
588
589
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp2Reg,
590
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, privateFlags), TR::Compiler->om.sizeofReferenceAddress()));
591
592
// The value for J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE is a generated value when VM code is created
593
// At the moment we are safe here, but it is better to be careful and avoid any unexpected behaviour
594
// Make sure this falls within the scope of andis
595
//
596
TR_ASSERT(J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE >= 0x00010000 && J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE <= 0x80000000,
597
"Concurrent mark active Value assumption broken.");
598
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andis_r, node, temp2Reg, temp2Reg, condReg, J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE >> 16);
599
600
//start of control flow
601
generateLabelInstruction(cg, TR::InstOpCode::label, node, startICF);
602
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, noChkLabel, condReg);
603
}
604
605
#if defined(TR_TARGET_64BIT)
606
uintptr_t card_size_shift = trailingZeroes((uint64_t)options->getGcCardSize());
607
#else
608
uintptr_t card_size_shift = trailingZeroes((uint32_t) options->getGcCardSize());
609
#endif
610
611
// dirty(activeCardTableBase + temp3Reg >> card_size_shift)
612
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp2Reg,
613
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, activeCardTableBase), TR::Compiler->om.sizeofReferenceAddress()));
614
#if defined(TR_TARGET_64BIT)
615
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicl, node, temp3Reg, temp3Reg, 64-card_size_shift, (CONSTANT64(1)<<(64-card_size_shift)) - CONSTANT64(1));
616
#else
617
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, temp3Reg, temp3Reg, 32 - card_size_shift, ((uint32_t) 0xFFFFFFFF) >> card_size_shift);
618
#endif
619
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, temp4Reg, CARD_DIRTY);
620
generateMemSrc1Instruction(cg, TR::InstOpCode::stb, node, TR::MemoryReference::createWithIndexReg(cg, temp2Reg, temp3Reg, 1), temp4Reg);
621
622
if (noChkLabel)
623
{
624
//end of control flow
625
noChkLabel->setEndInternalControlFlow();
626
generateLabelInstruction(cg, TR::InstOpCode::label, node, noChkLabel);
627
}
628
629
if (gcMode == gc_modron_wrtbar_cardmark_and_oldcheck)
630
{
631
//check for src in new space
632
generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, temp2Reg, bound1, srcReg);
633
634
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp2Reg, bound2);
635
generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, doneLabel, condReg);
636
}
637
}
638
else
639
{
640
if (gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_oldcheck)
641
{
642
//check for src in new space
643
generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, temp3Reg, bound1, srcReg);
644
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp3Reg, bound2);
645
generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, doneLabel, condReg);
646
}
647
}
648
649
TR::Instruction * i = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, temp2Reg, temp1Reg, condReg, J9_OBJECT_HEADER_REMEMBERED_MASK_FOR_TEST);
650
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, doneLabel, condReg);
651
}
652
else if (comp->getOptions()->realTimeGC())
653
{
654
if (!comp->getOption(TR_DisableInlineWriteBarriersRT))
655
{
656
// check if barrier is enabled: if disabled then branch around the rest
657
658
TR::MemoryReference *fragmentParentMR = TR::MemoryReference::createWithDisplacement(cg, cg->getMethodMetaDataRegister(),
659
fej9->thisThreadRememberedSetFragmentOffset() + fej9->getFragmentParentOffset(), TR::Compiler->om.sizeofReferenceAddress());
660
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp2Reg, fragmentParentMR);
661
662
TR::MemoryReference *globalFragmentIDMR = TR::MemoryReference::createWithDisplacement(cg, temp2Reg, fej9->getRememberedSetGlobalFragmentOffset(), TR::Compiler->om.sizeofReferenceAddress());
663
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg, globalFragmentIDMR);
664
665
// if barrier not enabled, nothing to do
666
generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpi, node, condReg, temp1Reg, NULLVALUE);
667
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg);
668
669
// now check if barrier absolutely necessary, according to GC: if it is, then make sure we go out-of-line
670
// if the global fragment index and local fragment index don't match, go to the snippet
671
TR::MemoryReference *localFragmentIndexMR = TR::MemoryReference::createWithDisplacement(cg, cg->getMethodMetaDataRegister(),
672
fej9->thisThreadRememberedSetFragmentOffset() + fej9->getLocalFragmentOffset(), TR::Compiler->om.sizeofReferenceAddress());
673
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp2Reg, localFragmentIndexMR);
674
generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpi, node, condReg, temp2Reg, NULLVALUE);
675
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, callLabel, condReg);
676
677
// null test on the reference we're about to store over: if it is null goto doneLabel
678
TR::InstOpCode::Mnemonic opCode = TR::InstOpCode::lwz;
679
int32_t size = 4;
680
if (comp->target().is64Bit() && !isCompressedRef)
681
{
682
opCode = TR::InstOpCode::ld;
683
size = 8;
684
}
685
generateTrg1MemInstruction(cg, opCode, node, temp1Reg, TR::MemoryReference::createWithDisplacement(cg, temp3Reg, 0, size));
686
generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpi, node, condReg, temp1Reg, NULLVALUE);
687
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg);
688
689
generateLabelInstruction(cg, TR::InstOpCode::label, node, callLabel);
690
}
691
}
692
693
generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t) wbRef->getSymbol()->castToMethodSymbol()->getMethodAddress(),
694
new (cg->trHeapMemory()) TR::RegisterDependencyConditions((uint8_t) 0, 0, cg->trMemory()), wbRef, NULL);
695
cg->machine()->setLinkRegisterKilled(true);
696
697
cg->stopUsingRegister(bound1);
698
cg->stopUsingRegister(bound2);
699
700
if (temp3RegIsNull && temp3Reg)
701
cg->stopUsingRegister(temp3Reg);
702
}
703
704
static void VMCardCheckEvaluator(TR::Node *node, TR::Register *dstReg, TR::Register *condReg, TR::Register *temp1Reg, TR::Register *temp2Reg, TR::Register *temp3Reg,
705
TR::RegisterDependencyConditions *deps, TR::CodeGenerator *cg)
706
{
707
TR::Compilation * comp = cg->comp();
708
// non-heap objects cannot be marked
709
// Make sure we really should be here
710
TR::Options *options = comp->getOptions();
711
TR::Node *wrtbarNode = NULL;
712
bool definitelyHeapObject = false, definitelyNonHeapObject = false;
713
auto gcMode = TR::Compiler->om.writeBarrierType();
714
715
if (node->getOpCodeValue() == TR::awrtbari || node->getOpCodeValue() == TR::awrtbar)
716
wrtbarNode = node;
717
else if (node->getOpCodeValue() == TR::ArrayStoreCHK)
718
wrtbarNode = node->getFirstChild();
719
720
if (wrtbarNode != NULL)
721
{
722
definitelyHeapObject = wrtbarNode->isHeapObjectWrtBar();
723
definitelyNonHeapObject = wrtbarNode->isNonHeapObjectWrtBar();
724
}
725
726
TR_ASSERT((gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_cardmark_incremental) && !definitelyNonHeapObject,
727
"VMCardCheckEvaluator: Invalid call to cardCheckEvaluator\n");
728
729
if (!definitelyNonHeapObject)
730
{
731
TR::Register *metaReg = cg->getMethodMetaDataRegister();
732
TR::LabelSymbol *noChkLabel = generateLabelSymbol(cg);
733
734
// Balanced policy must always dirty the card table.
735
//
736
if (gcMode != gc_modron_wrtbar_cardmark_incremental)
737
{
738
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,
739
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, privateFlags), TR::Compiler->om.sizeofReferenceAddress()));
740
741
// The value for J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE is a generated value when VM code is created
742
// At the moment we are safe here, but it is better to be careful and avoid any unexpected behaviour
743
// Make sure this falls within the scope of andis
744
//
745
TR_ASSERT(J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE >= 0x00010000 && J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE <= 0x80000000,
746
"Concurrent mark active Value assumption broken.");
747
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andis_r, node, temp1Reg, temp1Reg, condReg, J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE >> 16);
748
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, noChkLabel, condReg);
749
}
750
751
#if defined(TR_TARGET_64BIT)
752
uintptr_t card_size_shift = trailingZeroes((uint64_t)options->getGcCardSize());
753
#else
754
uintptr_t card_size_shift = trailingZeroes((uint32_t) options->getGcCardSize());
755
#endif
756
757
// temp3Reg = dstReg - heapBaseForBarrierRange0
758
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp3Reg,
759
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapBaseForBarrierRange0), TR::Compiler->om.sizeofReferenceAddress()));
760
generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, temp3Reg, temp3Reg, dstReg);
761
762
if (!definitelyHeapObject)
763
{
764
// if (temp3Reg >= heapSizeForBarrierRage0), object not in the heap
765
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,
766
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapSizeForBarrierRange0), TR::Compiler->om.sizeofReferenceAddress()));
767
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp3Reg, temp1Reg);
768
generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, noChkLabel, condReg);
769
}
770
771
// dirty(activeCardTableBase + temp3Reg >> card_size_shift)
772
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,
773
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, activeCardTableBase), TR::Compiler->om.sizeofReferenceAddress()));
774
#if defined(TR_TARGET_64BIT)
775
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicl, node, temp3Reg, temp3Reg, 64-card_size_shift, (CONSTANT64(1)<<(64-card_size_shift)) - CONSTANT64(1));
776
#else
777
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, temp3Reg, temp3Reg, 32 - card_size_shift, ((uint32_t) 0xFFFFFFFF) >> card_size_shift);
778
#endif
779
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, temp2Reg, CARD_DIRTY);
780
generateMemSrc1Instruction(cg, TR::InstOpCode::stb, node, TR::MemoryReference::createWithIndexReg(cg, temp1Reg, temp3Reg, 1), temp2Reg);
781
782
generateLabelInstruction(cg, TR::InstOpCode::label, node, noChkLabel);
783
}
784
785
}
786
787
static void VMwrtbarEvaluator(TR::Node *node, TR::Register *srcReg, TR::Register *dstReg, TR::Register *dstAddrReg,
788
TR::RegisterDependencyConditions *conditions, bool srcNonNull, bool needDeps, bool isCompressedRef, TR::CodeGenerator *cg, TR::Register *flagsReg = NULL)
789
{
790
TR::Compilation *comp = cg->comp();
791
auto gcMode = TR::Compiler->om.writeBarrierType();
792
bool doWrtBar = (gcMode == gc_modron_wrtbar_satb || gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always
793
|| comp->getOptions()->realTimeGC());
794
bool doCrdMrk = ((gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_cardmark_incremental) && !node->isNonHeapObjectWrtBar());
795
TR::LabelSymbol *label;
796
TR::Register *cr0, *temp1Reg, *temp2Reg, *temp3Reg = NULL, *temp4Reg = NULL;
797
uint8_t numRegs = (doWrtBar && doCrdMrk) ? 7 : 5;
798
799
//Also need to pass in destinationAddress to jitWriteBarrierStoreMetronome
800
if (comp->getOptions()->realTimeGC())
801
numRegs += 3;
802
803
if (doWrtBar || doCrdMrk)
804
numRegs += 4; //two extra deps for space boundaries
805
806
if ((!doWrtBar && !doCrdMrk) || (node->getOpCode().isWrtBar() && node->skipWrtBar()))
807
{
808
if (flagsReg)
809
cg->stopUsingRegister(flagsReg);
810
return;
811
}
812
if (flagsReg)
813
temp1Reg = flagsReg;
814
else
815
temp1Reg = cg->allocateRegister();
816
817
temp2Reg = cg->allocateRegister();
818
label = generateLabelSymbol(cg);
819
820
if (doWrtBar || doCrdMrk)
821
needDeps = true;
822
823
if (needDeps)
824
{
825
cr0 = cg->allocateRegister(TR_CCR);
826
conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(numRegs, numRegs, cg->trMemory());
827
TR::addDependency(conditions, cr0, TR::RealRegister::cr0, TR_CCR, cg);
828
TR::addDependency(conditions, dstReg, TR::RealRegister::gr3, TR_GPR, cg);
829
TR::addDependency(conditions, temp1Reg, TR::RealRegister::gr11, TR_GPR, cg);
830
if (comp->getOptions()->realTimeGC())
831
{
832
TR::addDependency(conditions, temp2Reg, TR::RealRegister::NoReg, TR_GPR, cg);
833
conditions->getPostConditions()->getRegisterDependency(3)->setExcludeGPR0(); //3=temp2Reg
834
TR::addDependency(conditions, dstAddrReg, TR::RealRegister::gr4, TR_GPR, cg);
835
temp3Reg = dstAddrReg;
836
}
837
else
838
TR::addDependency(conditions, temp2Reg, TR::RealRegister::NoReg, TR_GPR, cg);
839
}
840
else
841
cr0 = conditions->getPostConditions()->getRegisterDependency(2)->getRegister();
842
843
if (doWrtBar)
844
{
845
if (doCrdMrk)
846
{
847
temp3Reg = cg->allocateRegister();
848
temp4Reg = cg->allocateRegister();
849
if (needDeps)
850
{
851
TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);
852
TR::addDependency(conditions, temp4Reg, TR::RealRegister::NoReg, TR_GPR, cg);
853
conditions->getPostConditions()->getRegisterDependency(3)->setExcludeGPR0(); //3=temp2Reg
854
}
855
}
856
if (needDeps)
857
{
858
if (comp->getOptions()->realTimeGC())
859
TR::addDependency(conditions, srcReg, TR::RealRegister::gr5, TR_GPR, cg);
860
else
861
TR::addDependency(conditions, srcReg, TR::RealRegister::gr4, TR_GPR, cg);
862
}
863
if (!srcNonNull && !comp->getOptions()->realTimeGC())
864
{
865
generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpi, node, cr0, srcReg, NULLVALUE);
866
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, label, cr0);
867
}
868
869
VMnonNullSrcWrtBarCardCheckEvaluator(node, srcReg, dstReg, cr0, temp1Reg, temp2Reg, temp3Reg, temp4Reg, label, conditions, isCompressedRef, cg,
870
flagsReg != NULL);
871
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, label, conditions);
872
if (doCrdMrk)
873
{
874
cg->stopUsingRegister(temp3Reg);
875
cg->stopUsingRegister(temp4Reg);
876
}
877
else if (comp->getOptions()->realTimeGC())
878
cg->stopUsingRegister(temp3Reg);
879
}
880
else if (doCrdMrk)
881
{
882
temp3Reg = cg->allocateRegister();
883
if (needDeps)
884
{
885
TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);
886
conditions->getPostConditions()->getRegisterDependency(1)->setExcludeGPR0(); //1=dstReg
887
conditions->getPostConditions()->getRegisterDependency(2)->setExcludeGPR0(); //2=temp1Reg
888
}
889
890
VMCardCheckEvaluator(node, dstReg, cr0, temp1Reg, temp2Reg, temp3Reg, conditions, cg);
891
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, label, conditions);
892
cg->stopUsingRegister(temp3Reg);
893
}
894
if (needDeps)
895
{
896
cg->stopUsingRegister(cr0);
897
}
898
cg->stopUsingRegister(temp1Reg);
899
cg->stopUsingRegister(temp2Reg);
900
}
901
902
inline void generateLoadJ9Class(TR::Node* node, TR::Register* j9classReg, TR::Register *objReg, TR::CodeGenerator* cg)
903
{
904
if (TR::Compiler->om.compressObjectReferences())
905
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, j9classReg,
906
TR::MemoryReference::createWithDisplacement(cg, objReg, static_cast<int32_t>(TR::Compiler->om.offsetOfObjectVftField()), 4));
907
else
908
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, j9classReg,
909
TR::MemoryReference::createWithDisplacement(cg, objReg, static_cast<int32_t>(TR::Compiler->om.offsetOfObjectVftField()), TR::Compiler->om.sizeofReferenceAddress()));
910
TR::TreeEvaluator::generateVFTMaskInstruction(cg, node, j9classReg);
911
}
912
913
void
914
J9::Power::TreeEvaluator::generateFillInDataBlockSequenceForUnresolvedField(TR::CodeGenerator *cg, TR::Node *node, TR::Snippet *dataSnippet, bool isWrite, TR::Register *sideEffectRegister, TR::Register *dataSnippetRegister)
915
{
916
TR::Compilation *comp = cg->comp();
917
TR::SymbolReference *symRef = node->getSymbolReference();
918
bool is64Bit = comp->target().is64Bit();
919
bool isStatic = symRef->getSymbol()->getKind() == TR::Symbol::IsStatic;
920
921
TR_RuntimeHelper helperIndex = isWrite? (isStatic ? TR_jitResolveStaticFieldSetterDirect: TR_jitResolveFieldSetterDirect):
922
(isStatic ? TR_jitResolveStaticFieldDirect: TR_jitResolveFieldDirect);
923
924
TR::Linkage *linkage = cg->getLinkage(runtimeHelperLinkage(helperIndex));
925
auto linkageProperties = linkage->getProperties();
926
intptr_t offsetInDataBlock = isStatic ? offsetof(J9JITWatchedStaticFieldData, fieldAddress): offsetof(J9JITWatchedInstanceFieldData, offset);
927
928
929
TR::LabelSymbol* startLabel = generateLabelSymbol(cg);
930
TR::LabelSymbol* endLabel = generateLabelSymbol(cg);
931
TR::LabelSymbol* unresolvedLabel = generateLabelSymbol(cg);
932
startLabel->setStartInternalControlFlow();
933
endLabel->setEndInternalControlFlow();
934
935
TR::Register *cpIndexReg = cg->allocateRegister();
936
TR::Register *resultReg = cg->allocateRegister();
937
TR::Register *scratchReg = cg->allocateRegister();
938
TR::Register *jumpReg = cg->allocateRegister();
939
940
// Check if snippet has been loaded
941
if (!isStatic && !static_cast<TR::J9PPCWatchedInstanceFieldSnippet *>(dataSnippet)->isSnippetLoaded() ||
942
(isStatic && !static_cast<TR::J9PPCWatchedStaticFieldSnippet *>(dataSnippet)->isSnippetLoaded()))
943
loadFieldWatchSnippet(cg, node, dataSnippet, dataSnippetRegister, scratchReg, !isStatic);
944
945
946
// Setup Dependencies
947
// dataSnippetRegister is always used during OOL sequence.
948
// Requires two argument registers: resultReg and cpIndexReg.
949
// Static requires an extra arugment fieldClassReg
950
// jumpReg used by trampoline
951
uint8_t numOfConditions = isStatic? 5 : 4;
952
TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(numOfConditions, numOfConditions, cg->trMemory());
953
954
deps->addPreCondition(dataSnippetRegister, TR::RealRegister::NoReg);
955
deps->addPostCondition(dataSnippetRegister, TR::RealRegister::NoReg);
956
957
TR_PPCOutOfLineCodeSection *generateReportOOL = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(unresolvedLabel, endLabel, cg);
958
cg->getPPCOutOfLineCodeSectionList().push_front(generateReportOOL);
959
960
generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);
961
962
// Compare J9JITWatchedInstanceFieldData.offset or J9JITWatchedStaticFieldData.fieldAddress (Depending on Instance of Static)
963
// Load value from dataSnippetRegister + offsetInDataBlock then compare and branch
964
TR::Register *cndReg = cg->allocateRegister(TR_CCR);
965
generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, scratchReg,
966
TR::MemoryReference::createWithDisplacement(cg, dataSnippetRegister, offsetInDataBlock, TR::Compiler->om.sizeofReferenceAddress()));
967
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::Op_cmpi, node, cndReg, scratchReg, -1);
968
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, unresolvedLabel, cndReg);
969
970
generateReportOOL->swapInstructionListsWithCompilation();
971
972
generateLabelInstruction(cg, TR::InstOpCode::label, node, unresolvedLabel);
973
974
bool isSideEffectReg = false;
975
if (isStatic)
976
{
977
// Fill in J9JITWatchedStaticFieldData.fieldClass
978
TR::Register *fieldClassReg = NULL;
979
980
if (isWrite)
981
{
982
fieldClassReg = cg->allocateRegister();
983
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, fieldClassReg,
984
TR::MemoryReference::createWithDisplacement(cg, sideEffectRegister, comp->fej9()->getOffsetOfClassFromJavaLangClassField(), TR::Compiler->om.sizeofReferenceAddress()));
985
}
986
else
987
{
988
isSideEffectReg = true;
989
fieldClassReg = sideEffectRegister;
990
}
991
TR::MemoryReference *memRef = TR::MemoryReference::createWithDisplacement(cg, dataSnippetRegister, offsetof(J9JITWatchedStaticFieldData, fieldClass), TR::Compiler->om.sizeofReferenceAddress());
992
993
// Store value to dataSnippetRegister + offset of fieldClass
994
generateMemSrc1Instruction(cg, TR::InstOpCode::Op_st, node, memRef, fieldClassReg);
995
deps->addPreCondition(fieldClassReg, TR::RealRegister::NoReg);
996
deps->addPostCondition(fieldClassReg, TR::RealRegister::NoReg);
997
if (!isSideEffectReg)
998
cg->stopUsingRegister(fieldClassReg);
999
}
1000
1001
TR::ResolvedMethodSymbol *methodSymbol = node->getByteCodeInfo().getCallerIndex() == -1 ? comp->getMethodSymbol(): comp->getInlinedResolvedMethodSymbol(node->getByteCodeInfo().getCallerIndex());
1002
1003
// Store cpAddressReg
1004
// TODO: Replace when AOT TR_ConstantPool Discontiguous support is enabled
1005
//loadAddressConstant(cg, node, (uintptr_t)methodSymbol->getResolvedMethod()->constantPool(), resultReg, NULL, false, TR_ConstantPool);
1006
loadAddressConstant(cg, comp->compileRelocatableCode(), node, reinterpret_cast<uintptr_t>(methodSymbol->getResolvedMethod()->constantPool()), resultReg);
1007
loadConstant(cg, node, symRef->getCPIndex(), cpIndexReg);
1008
1009
// cpAddress is the first argument of VMHelper
1010
deps->addPreCondition(resultReg, TR::RealRegister::gr3);
1011
deps->addPostCondition(resultReg, TR::RealRegister::gr3);
1012
// cpIndexReg is the second argument
1013
deps->addPreCondition(cpIndexReg, TR::RealRegister::gr4);
1014
deps->addPostCondition(cpIndexReg, TR::RealRegister::gr4);
1015
// jumpReg is used in trampoline to store callee address
1016
deps->addPreCondition(jumpReg, TR::RealRegister::gr11);
1017
deps->addPostCondition(jumpReg, TR::RealRegister::gr11);
1018
1019
// Generate helper address and branch
1020
TR::SymbolReference *helperSym = comp->getSymRefTab()->findOrCreateRuntimeHelper(helperIndex);
1021
TR::Instruction *call = generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, reinterpret_cast<uintptr_t>(helperSym->getMethodAddress()), deps, helperSym);
1022
call->PPCNeedsGCMap(linkageProperties.getPreservedRegisterMapForGC());
1023
1024
/*
1025
* For instance field offset, the result returned by the vmhelper includes header size.
1026
* subtract the header size to get the offset needed by field watch helpers
1027
*/
1028
if (!isStatic)
1029
addConstantToInteger(node, resultReg, resultReg , -TR::Compiler->om.objectHeaderSizeInBytes(), cg);
1030
1031
// store result into J9JITWatchedStaticFieldData.fieldAddress / J9JITWatchedInstanceFieldData.offset
1032
TR::MemoryReference* dataRef = TR::MemoryReference::createWithDisplacement(cg, dataSnippetRegister, offsetInDataBlock, TR::Compiler->om.sizeofReferenceAddress());
1033
generateMemSrc1Instruction(cg, TR::InstOpCode::Op_st, node, dataRef, resultReg);
1034
1035
generateLabelInstruction(cg, TR::InstOpCode::b, node, endLabel);
1036
1037
generateReportOOL->swapInstructionListsWithCompilation();
1038
1039
generateLabelInstruction(cg, TR::InstOpCode::label, node, endLabel);
1040
1041
cg->stopUsingRegister(scratchReg);
1042
cg->stopUsingRegister(cndReg);
1043
cg->stopUsingRegister(cpIndexReg);
1044
cg->stopUsingRegister(resultReg);
1045
cg->stopUsingRegister(jumpReg);
1046
1047
}
1048
1049
/*
1050
* Generate the reporting field access helper call with required arguments
1051
*
1052
* jitReportInstanceFieldRead
1053
* arg1 pointer to static data block
1054
* arg2 object being read
1055
*
1056
* jitReportInstanceFieldWrite
1057
* arg1 pointer to static data block
1058
* arg2 object being written to
1059
* arg3 pointer to value being written
1060
*
1061
* jitReportStaticFieldRead
1062
* arg1 pointer to static data block
1063
*
1064
* jitReportStaticFieldWrite
1065
* arg1 pointer to static data block
1066
* arg2 pointer to value being written
1067
*
1068
*/
1069
void generateReportFieldAccessOutlinedInstructions(TR::Node *node, TR::LabelSymbol *endLabel, TR::Register *dataBlockReg, bool isWrite, TR::CodeGenerator *cg, TR::Register *sideEffectRegister, TR::Register *valueReg)
1070
{
1071
TR::Compilation *comp = cg->comp();
1072
bool isInstanceField = node->getOpCode().isIndirect();
1073
1074
TR_RuntimeHelper helperIndex = isWrite ? (isInstanceField ? TR_jitReportInstanceFieldWrite: TR_jitReportStaticFieldWrite):
1075
(isInstanceField ? TR_jitReportInstanceFieldRead: TR_jitReportStaticFieldRead);
1076
1077
TR::Linkage *linkage = cg->getLinkage(runtimeHelperLinkage(helperIndex));
1078
auto linkageProperties = linkage->getProperties();
1079
TR::Register *valueReferenceReg = NULL;
1080
TR::Register *jumpReg = cg->allocateRegister();
1081
1082
// First argument is always the data block.
1083
// One register used by trampoline
1084
uint8_t numOfConditions = 2;
1085
// Instance field report needs the base object
1086
if (isInstanceField)
1087
numOfConditions++;
1088
// Field write report needs:
1089
// value being written
1090
// the reference to the value being written
1091
if (isWrite)
1092
numOfConditions += 2;
1093
// Register Pair may be needed
1094
if(comp->target().is32Bit())
1095
numOfConditions++;
1096
1097
TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory())TR::RegisterDependencyConditions(numOfConditions, numOfConditions, cg->trMemory());
1098
1099
/*
1100
* For reporting field write, reference to the valueNode is needed so we need to store
1101
* the value on to a stack location first and pass the stack location address as an arguement
1102
* to the VM helper
1103
*/
1104
if (isWrite)
1105
{
1106
TR::DataType dt = node->getDataType();
1107
int32_t elementSize = dt == TR::Address ? TR::Compiler->om.sizeofReferenceField() : TR::Symbol::convertTypeToSize(dt);
1108
TR::InstOpCode::Mnemonic storeOp = getLoadOrStoreFromDataType(cg, dt, elementSize, node->getOpCode().isUnsigned(), false);
1109
TR::SymbolReference *location = cg->allocateLocalTemp(dt);
1110
TR::MemoryReference *valueMR = TR::MemoryReference::createWithSymRef(cg, node, location, node->getSize());
1111
if (!valueReg->getRegisterPair())
1112
{
1113
generateMemSrc1Instruction(cg, storeOp, node, valueMR, valueReg);
1114
deps->addPreCondition(valueReg, TR::RealRegister::NoReg);
1115
deps->addPostCondition(valueReg, TR::RealRegister::NoReg);
1116
valueReferenceReg = cg->allocateRegister();
1117
}
1118
else
1119
{
1120
TR::MemoryReference *tempMR2 = TR::MemoryReference::createWithMemRef(cg, node, *valueMR, 4, 4);
1121
generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, valueMR, valueReg->getHighOrder());
1122
generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, tempMR2, valueReg->getLowOrder());
1123
deps->addPreCondition(valueReg->getHighOrder(), TR::RealRegister::NoReg);
1124
deps->addPostCondition(valueReg->getHighOrder(), TR::RealRegister::NoReg);
1125
valueReferenceReg = valueReg->getLowOrder();
1126
}
1127
1128
// store the stack location into a register
1129
generateTrg1MemInstruction(cg, TR::InstOpCode::addi2, node, valueReferenceReg, valueMR);
1130
}
1131
1132
// First Argument - DataBlock
1133
deps->addPreCondition(dataBlockReg, TR::RealRegister::gr3);
1134
deps->addPostCondition(dataBlockReg, TR::RealRegister::gr3);
1135
1136
// Second Argument
1137
if (isInstanceField)
1138
{
1139
deps->addPreCondition(sideEffectRegister, TR::RealRegister::gr4);
1140
deps->addPostCondition(sideEffectRegister, TR::RealRegister::gr4);
1141
}
1142
else if (isWrite)
1143
{
1144
deps->addPreCondition(valueReferenceReg, TR::RealRegister::gr4);
1145
deps->addPostCondition(valueReferenceReg, TR::RealRegister::gr4);
1146
}
1147
1148
// Third Argument
1149
if (isInstanceField && isWrite)
1150
{
1151
deps->addPreCondition(valueReferenceReg, TR::RealRegister::gr5);
1152
deps->addPostCondition(valueReferenceReg, TR::RealRegister::gr5);
1153
}
1154
1155
// Register ued by trampoline to store callee address
1156
deps->addPreCondition(jumpReg, TR::RealRegister::gr11);
1157
deps->addPostCondition(jumpReg, TR::RealRegister::gr11);
1158
1159
// Generate branch instruction to jump into helper
1160
TR::SymbolReference *helperSym = comp->getSymRefTab()->findOrCreateRuntimeHelper(helperIndex);
1161
TR::Instruction *call = generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, reinterpret_cast<uintptr_t>(helperSym->getMethodAddress()), deps, helperSym);
1162
call->PPCNeedsGCMap(linkageProperties.getPreservedRegisterMapForGC());
1163
1164
generateLabelInstruction(cg, TR::InstOpCode::b, node, endLabel);
1165
1166
cg->stopUsingRegister(valueReferenceReg);
1167
cg->stopUsingRegister(jumpReg);
1168
1169
}
1170
1171
void loadFieldWatchSnippet(TR::CodeGenerator *cg, TR::Node *node, TR::Snippet *dataSnippet, TR::Register *snippetReg, TR::Register *scratchReg, bool isInstanceField)
1172
{
1173
TR::Compilation *comp = cg->comp();
1174
int32_t beginIndex = PTOC_FULL_INDEX;
1175
1176
cg->fixedLoadLabelAddressIntoReg(node, snippetReg, dataSnippet->getSnippetLabel());
1177
1178
// Loaded Snippet
1179
if (!isInstanceField)
1180
{
1181
static_cast<TR::J9PPCWatchedStaticFieldSnippet *>(dataSnippet)->setLoadSnippet();
1182
}
1183
else
1184
{
1185
static_cast<TR::J9PPCWatchedInstanceFieldSnippet *>(dataSnippet)->setLoadSnippet();
1186
}
1187
}
1188
1189
TR::Snippet *
1190
J9::Power::TreeEvaluator::getFieldWatchInstanceSnippet(TR::CodeGenerator *cg, TR::Node *node, J9Method *m, UDATA loc, UDATA os)
1191
{
1192
return new (cg->trHeapMemory()) TR::J9PPCWatchedInstanceFieldSnippet(cg, node, m, loc, os);
1193
}
1194
1195
TR::Snippet *
1196
J9::Power::TreeEvaluator::getFieldWatchStaticSnippet(TR::CodeGenerator *cg, TR::Node *node, J9Method *m, UDATA loc, void *fieldAddress, J9Class *fieldClass)
1197
{
1198
return new (cg->trHeapMemory()) TR::J9PPCWatchedStaticFieldSnippet(cg, node, m, loc, fieldAddress, fieldClass);
1199
}
1200
1201
void
1202
J9::Power::TreeEvaluator::generateTestAndReportFieldWatchInstructions(TR::CodeGenerator *cg, TR::Node *node, TR::Snippet *dataSnippet, bool isWrite, TR::Register *sideEffectRegister, TR::Register *valueReg, TR::Register *dataSnippetRegister)
1203
{
1204
bool isInstanceField = node->getOpCode().isIndirect();
1205
TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());
1206
1207
TR::Register *scratchReg = cg->allocateRegister();
1208
1209
// Check if snippet has been loaded
1210
if (isInstanceField && !static_cast<TR::J9PPCWatchedInstanceFieldSnippet *>(dataSnippet)->isSnippetLoaded() ||
1211
(!isInstanceField && !static_cast<TR::J9PPCWatchedStaticFieldSnippet *>(dataSnippet)->isSnippetLoaded()))
1212
loadFieldWatchSnippet(cg, node, dataSnippet, dataSnippetRegister, scratchReg, isInstanceField);
1213
1214
TR::LabelSymbol* startLabel = generateLabelSymbol(cg);
1215
TR::LabelSymbol* endLabel = generateLabelSymbol(cg);
1216
TR::LabelSymbol* fieldReportLabel = generateLabelSymbol(cg);
1217
startLabel->setStartInternalControlFlow();
1218
endLabel->setEndInternalControlFlow();
1219
1220
generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);
1221
1222
TR_PPCOutOfLineCodeSection *generateReportOOL = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(fieldReportLabel, endLabel, cg);
1223
cg->getPPCOutOfLineCodeSectionList().push_front(generateReportOOL);
1224
1225
TR::Register *fieldClassReg = NULL;
1226
bool isSideEffectReg = false;
1227
// Load fieldClass
1228
if (isInstanceField)
1229
{
1230
fieldClassReg = cg->allocateRegister();
1231
generateLoadJ9Class(node, fieldClassReg, sideEffectRegister, cg);
1232
}
1233
else if (!(node->getSymbolReference()->isUnresolved()))
1234
{
1235
fieldClassReg = cg->allocateRegister();
1236
// During Non-AOT (JIT and JITServer) compilation the fieldClass has been populated inside the dataSnippet during compilation.
1237
// During AOT compilation the fieldClass must be loaded from the snippet. The fieldClass in an AOT body is invalid.
1238
if (cg->needClassAndMethodPointerRelocations())
1239
{
1240
// Load FieldClass from snippet
1241
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, fieldClassReg,
1242
TR::MemoryReference::createWithDisplacement(cg, dataSnippetRegister, offsetof(J9JITWatchedStaticFieldData, fieldClass),
1243
TR::Compiler->om.sizeofReferenceAddress()));
1244
}
1245
else
1246
{
1247
J9Class * fieldClass = static_cast<TR::J9PPCWatchedStaticFieldSnippet *>(dataSnippet)->getFieldClass();
1248
loadAddressConstant(cg, false, node, reinterpret_cast<uintptr_t>(fieldClass), fieldClassReg);
1249
}
1250
}
1251
else
1252
{
1253
// Unresolved
1254
if (isWrite)
1255
{
1256
fieldClassReg = cg->allocateRegister();
1257
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, fieldClassReg,
1258
TR::MemoryReference::createWithDisplacement(cg, sideEffectRegister, fej9->getOffsetOfClassFromJavaLangClassField(), TR::Compiler->om.sizeofReferenceAddress()));
1259
}
1260
else
1261
{
1262
isSideEffectReg = true;
1263
fieldClassReg = sideEffectRegister;
1264
}
1265
}
1266
1267
TR::MemoryReference *classFlagsMemRef = TR::MemoryReference::createWithDisplacement(cg, fieldClassReg, static_cast<uintptr_t>(fej9->getOffsetOfClassFlags()), 4);
1268
1269
TR::Register *cndReg = cg->allocateRegister(TR_CCR);
1270
generateTrg1MemInstruction(cg,TR::InstOpCode::lwz, node, scratchReg, classFlagsMemRef);
1271
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, scratchReg, scratchReg, cndReg, J9ClassHasWatchedFields);
1272
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, fieldReportLabel, cndReg);
1273
1274
generateReportOOL->swapInstructionListsWithCompilation();
1275
1276
generateLabelInstruction(cg, TR::InstOpCode::label, node, fieldReportLabel);
1277
generateReportFieldAccessOutlinedInstructions(node, endLabel, dataSnippetRegister, isWrite, cg, sideEffectRegister, valueReg);
1278
1279
generateReportOOL->swapInstructionListsWithCompilation();
1280
1281
generateLabelInstruction(cg, TR::InstOpCode::label, node, endLabel);
1282
1283
cg->stopUsingRegister(cndReg);
1284
cg->stopUsingRegister(scratchReg);
1285
if (!isSideEffectReg)
1286
cg->stopUsingRegister(fieldClassReg);
1287
cg->stopUsingRegister(valueReg);
1288
1289
cg->machine()->setLinkRegisterKilled(true);
1290
1291
}
1292
1293
TR::Register *J9::Power::TreeEvaluator::awrtbarEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1294
{
1295
TR::Compilation *comp = cg->comp();
1296
TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());
1297
TR::Register *valueReg = cg->evaluate(node->getFirstChild());
1298
TR::Register *sideEffectRegister = cg->evaluate(node->getSecondChild());
1299
if (comp->getOption(TR_EnableFieldWatch) && !node->getSymbolReference()->getSymbol()->isShadow())
1300
{
1301
TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg);
1302
}
1303
1304
if (comp->isOptServer() && !comp->compileRelocatableCode() && !comp->getOptions()->realTimeGC())
1305
{
1306
if (!comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P8))
1307
{
1308
static bool disableOutlinedWrtbar = feGetEnv("TR_ppcDisableOutlinedWriteBarrier") != NULL;
1309
if (!disableOutlinedWrtbar)
1310
{
1311
return outlinedHelperWrtbarEvaluator(node, cg);
1312
}
1313
}
1314
else
1315
{
1316
static bool enableOutlinedWrtbar = feGetEnv("TR_ppcEnableOutlinedWriteBarrier") != NULL;
1317
if (enableOutlinedWrtbar)
1318
{
1319
return outlinedHelperWrtbarEvaluator(node, cg);
1320
}
1321
}
1322
}
1323
1324
TR::Register *destinationRegister = cg->evaluate(node->getSecondChild());
1325
TR::Register *flagsReg = NULL;
1326
TR::Node *firstChild = node->getFirstChild();
1327
TR::Register *sourceRegister;
1328
bool killSource = false;
1329
1330
if (firstChild->getReferenceCount() > 1 && firstChild->getRegister() != NULL)
1331
{
1332
if (!firstChild->getRegister()->containsInternalPointer())
1333
sourceRegister = cg->allocateCollectedReferenceRegister();
1334
else
1335
{
1336
sourceRegister = cg->allocateRegister();
1337
sourceRegister->setPinningArrayPointer(firstChild->getRegister()->getPinningArrayPointer());
1338
sourceRegister->setContainsInternalPointer();
1339
}
1340
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, sourceRegister, firstChild->getRegister());
1341
killSource = true;
1342
}
1343
else
1344
sourceRegister = cg->evaluate(firstChild);
1345
1346
if (!node->skipWrtBar() && !node->hasUnresolvedSymbolReference()
1347
&& (TR::Compiler->om.writeBarrierType() == gc_modron_wrtbar_oldcheck || TR::Compiler->om.writeBarrierType() == gc_modron_wrtbar_cardmark_and_oldcheck))
1348
{
1349
flagsReg = cg->allocateRegister();
1350
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, flagsReg, TR::MemoryReference::createWithDisplacement(cg, destinationRegister, getOffsetOfJ9ObjectFlags(), 4));
1351
}
1352
1353
// RealTimeGC write barriers occur BEFORE the store
1354
if (comp->getOptions()->realTimeGC())
1355
{
1356
TR::Register *destinationAddressRegister = cg->allocateRegister();
1357
1358
TR::LoadStoreHandler::generateComputeAddressSequence(cg, destinationAddressRegister, node);
1359
VMwrtbarEvaluator(node, sourceRegister, destinationRegister, destinationAddressRegister, NULL, firstChild->isNonNull(), true, false, cg);
1360
TR::LoadStoreHandler::generateStoreAddressSequence(cg, sourceRegister, node, destinationAddressRegister, TR::InstOpCode::Op_st, TR::Compiler->om.sizeofReferenceAddress());
1361
1362
cg->stopUsingRegister(destinationAddressRegister);
1363
}
1364
else
1365
{
1366
TR::LoadStoreHandler::generateStoreNodeSequence(cg, sourceRegister, node, TR::InstOpCode::Op_st, TR::Compiler->om.sizeofReferenceAddress());
1367
VMwrtbarEvaluator(node, sourceRegister, destinationRegister, NULL, NULL, firstChild->isNonNull(), true, false, cg, flagsReg);
1368
}
1369
1370
if (killSource)
1371
cg->stopUsingRegister(sourceRegister);
1372
1373
cg->decReferenceCount(node->getFirstChild());
1374
cg->decReferenceCount(node->getSecondChild());
1375
1376
return NULL;
1377
}
1378
1379
TR::Register *J9::Power::TreeEvaluator::awrtbariEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1380
{
1381
TR::Compilation *comp = cg->comp();
1382
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
1383
1384
TR::Node *valueNode = NULL;
1385
TR::TreeEvaluator::getIndirectWrtbarValueNode(cg, node, valueNode, false);
1386
TR::Register *valueReg = cg->evaluate(valueNode);
1387
TR::Register *sideEffectRegister = cg->evaluate(node->getThirdChild());
1388
1389
TR::Register *destinationRegister = cg->evaluate(node->getChild(2));
1390
TR::Node *secondChild = node->getSecondChild();
1391
TR::Register *sourceRegister;
1392
TR::Register *flagsReg = NULL;
1393
bool killSource = false;
1394
1395
bool usingCompressedPointers = false;
1396
bool bumpedRefCount = false;
1397
1398
if (comp->getOption(TR_EnableFieldWatch) && !node->getSymbolReference()->getSymbol()->isArrayShadowSymbol())
1399
{
1400
// The Third child (sideEffectNode) and valueReg's node is also used by the store evaluator below.
1401
// The store evaluator will also evaluate+decrement it. In order to avoid double
1402
// decrementing the node we skip doing it here and let the store evaluator do it.
1403
TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg);
1404
}
1405
1406
if (comp->useCompressedPointers() && (node->getSymbolReference()->getSymbol()->getDataType() == TR::Address) && (node->getSecondChild()->getDataType() != TR::Address))
1407
{
1408
usingCompressedPointers = true;
1409
while (secondChild->getNumChildren() && secondChild->getOpCodeValue() != TR::a2l)
1410
secondChild = secondChild->getFirstChild();
1411
if (secondChild->getNumChildren())
1412
secondChild = secondChild->getFirstChild();
1413
}
1414
1415
int32_t sizeofMR = TR::Compiler->om.sizeofReferenceAddress();
1416
if (usingCompressedPointers)
1417
sizeofMR = TR::Compiler->om.sizeofReferenceField();
1418
1419
TR::Register *compressedReg;
1420
if (secondChild->getReferenceCount() > 1 && secondChild->getRegister() != NULL)
1421
{
1422
if (!secondChild->getRegister()->containsInternalPointer())
1423
sourceRegister = cg->allocateCollectedReferenceRegister();
1424
else
1425
{
1426
sourceRegister = cg->allocateRegister();
1427
sourceRegister->setPinningArrayPointer(secondChild->getRegister()->getPinningArrayPointer());
1428
sourceRegister->setContainsInternalPointer();
1429
}
1430
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, sourceRegister, secondChild->getRegister());
1431
killSource = true;
1432
compressedReg = sourceRegister;
1433
if (usingCompressedPointers)
1434
compressedReg = cg->evaluate(node->getSecondChild());
1435
}
1436
else
1437
{
1438
sourceRegister = cg->evaluate(secondChild);
1439
compressedReg = sourceRegister;
1440
if (usingCompressedPointers)
1441
compressedReg = cg->evaluate(node->getSecondChild());
1442
}
1443
1444
if (!node->skipWrtBar() && !node->hasUnresolvedSymbolReference()
1445
&& (TR::Compiler->om.writeBarrierType() == gc_modron_wrtbar_oldcheck || TR::Compiler->om.writeBarrierType() == gc_modron_wrtbar_cardmark_and_oldcheck))
1446
{
1447
flagsReg = cg->allocateRegister();
1448
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, flagsReg, TR::MemoryReference::createWithDisplacement(cg, destinationRegister, getOffsetOfJ9ObjectFlags(), 4));
1449
}
1450
1451
TR::InstOpCode::Mnemonic storeOp = usingCompressedPointers ? TR::InstOpCode::stw : TR::InstOpCode::Op_st;
1452
TR::Register *storeRegister = usingCompressedPointers ? compressedReg : sourceRegister;
1453
1454
// RealTimeGC write barriers occur BEFORE the store
1455
if (comp->getOptions()->realTimeGC())
1456
{
1457
TR::Register *destinationAddressRegister = cg->allocateRegister();
1458
1459
TR::LoadStoreHandler::generateComputeAddressSequence(cg, destinationAddressRegister, node);
1460
VMwrtbarEvaluator(node, sourceRegister, destinationRegister, destinationAddressRegister, NULL, secondChild->isNonNull(), true, usingCompressedPointers, cg);
1461
TR::LoadStoreHandler::generateStoreAddressSequence(cg, storeRegister, node, destinationAddressRegister, storeOp, sizeofMR);
1462
1463
cg->stopUsingRegister(destinationAddressRegister);
1464
}
1465
else
1466
{
1467
TR::LoadStoreHandler::generateStoreNodeSequence(cg, storeRegister, node, storeOp, sizeofMR);
1468
VMwrtbarEvaluator(node, sourceRegister, destinationRegister, NULL, NULL, secondChild->isNonNull(), true, usingCompressedPointers, cg, flagsReg);
1469
}
1470
1471
if (killSource)
1472
cg->stopUsingRegister(sourceRegister);
1473
1474
cg->decReferenceCount(node->getSecondChild());
1475
cg->decReferenceCount(node->getChild(2));
1476
1477
if (comp->useCompressedPointers())
1478
node->setStoreAlreadyEvaluated(true);
1479
1480
return NULL;
1481
}
1482
1483
TR::Register *iGenerateSoftwareReadBarrier(TR::Node *node, TR::CodeGenerator *cg)
1484
{
1485
#ifndef OMR_GC_CONCURRENT_SCAVENGER
1486
TR_ASSERT_FATAL(false, "Concurrent Scavenger not supported.");
1487
#else
1488
TR::Compilation *comp = cg->comp();
1489
1490
TR::Register *objReg = cg->allocateRegister();
1491
TR::Register *locationReg = cg->allocateRegister();
1492
TR::Register *evacuateReg = cg->allocateRegister();
1493
TR::Register *r3Reg = cg->allocateRegister();
1494
TR::Register *r11Reg = cg->allocateRegister();
1495
TR::Register *metaReg = cg->getMethodMetaDataRegister();
1496
TR::Register *condReg = cg->allocateRegister(TR_CCR);
1497
1498
TR::LabelSymbol *startLabel = generateLabelSymbol(cg);
1499
TR::LabelSymbol *endLabel = generateLabelSymbol(cg);
1500
startLabel->setStartInternalControlFlow();
1501
endLabel->setEndInternalControlFlow();
1502
1503
TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 7, cg->trMemory());
1504
deps->addPostCondition(objReg, TR::RealRegister::NoReg);
1505
deps->addPostCondition(locationReg, TR::RealRegister::gr4); //TR_softwareReadBarrier helper needs this in gr4.
1506
deps->addPostCondition(evacuateReg, TR::RealRegister::NoReg);
1507
deps->addPostCondition(r3Reg, TR::RealRegister::gr3);
1508
deps->addPostCondition(r11Reg, TR::RealRegister::gr11);
1509
deps->addPostCondition(metaReg, TR::RealRegister::NoReg);
1510
deps->addPostCondition(condReg, TR::RealRegister::NoReg);
1511
1512
if (node->getSymbolReference()->getSymbol()->isInternalPointer())
1513
{
1514
objReg->setPinningArrayPointer(node->getSymbolReference()->getSymbol()->castToInternalPointerAutoSymbol()->getPinningArrayPointer());
1515
objReg->setContainsInternalPointer();
1516
}
1517
1518
node->setRegister(objReg);
1519
1520
TR::LoadStoreHandler::generateComputeAddressSequence(cg, locationReg, node);
1521
1522
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, objReg, TR::MemoryReference::createWithDisplacement(cg, locationReg, 0, 4));
1523
1524
generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);
1525
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, evacuateReg,
1526
TR::MemoryReference::createWithDisplacement(cg, metaReg, comp->fej9()->thisThreadGetEvacuateBaseAddressOffset(), 4));
1527
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmpl4, node, condReg, objReg, evacuateReg);
1528
generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, endLabel, condReg);
1529
1530
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, evacuateReg,
1531
TR::MemoryReference::createWithDisplacement(cg, metaReg, comp->fej9()->thisThreadGetEvacuateTopAddressOffset(), 4));
1532
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmpl4, node, condReg, objReg, evacuateReg);
1533
generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, endLabel, condReg);
1534
1535
// TR_softwareReadBarrier helper expects the vmThread in r3.
1536
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, r3Reg, metaReg);
1537
1538
TR::SymbolReference *helperSym = comp->getSymRefTab()->findOrCreateRuntimeHelper(TR_softwareReadBarrier);
1539
generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)helperSym->getMethodAddress(), deps, helperSym);
1540
1541
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, objReg, TR::MemoryReference::createWithDisplacement(cg, locationReg, 0, 4));
1542
1543
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, endLabel, deps);
1544
1545
// TODO: Allow this to be patched or skipped at runtime for unresolved symrefs
1546
if (node->getSymbol()->isSyncVolatile() && comp->target().isSMP())
1547
{
1548
generateInstruction(cg, comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P7) ? TR::InstOpCode::lwsync : TR::InstOpCode::isync, node);
1549
}
1550
1551
cg->insertPrefetchIfNecessary(node, objReg);
1552
1553
cg->stopUsingRegister(evacuateReg);
1554
cg->stopUsingRegister(locationReg);
1555
cg->stopUsingRegister(r3Reg);
1556
cg->stopUsingRegister(r11Reg);
1557
cg->stopUsingRegister(condReg);
1558
1559
cg->machine()->setLinkRegisterKilled(true);
1560
1561
return objReg;
1562
#endif
1563
}
1564
1565
TR::Register *aGenerateSoftwareReadBarrier(TR::Node *node, TR::CodeGenerator *cg)
1566
{
1567
#ifndef OMR_GC_CONCURRENT_SCAVENGER
1568
TR_ASSERT_FATAL(false, "Concurrent Scavenger not supported.");
1569
#else
1570
TR::Compilation *comp = cg->comp();
1571
1572
TR::Register *tempReg;
1573
TR::Register *locationReg = cg->allocateRegister();
1574
TR::Register *evacuateReg = cg->allocateRegister();
1575
TR::Register *r3Reg = cg->allocateRegister();
1576
TR::Register *r11Reg = cg->allocateRegister();
1577
TR::Register *metaReg = cg->getMethodMetaDataRegister();
1578
TR::Register *condReg = cg->allocateRegister(TR_CCR);
1579
1580
if (!node->getSymbolReference()->getSymbol()->isInternalPointer())
1581
{
1582
if (node->getSymbolReference()->getSymbol()->isNotCollected())
1583
tempReg = cg->allocateRegister();
1584
else
1585
tempReg = cg->allocateCollectedReferenceRegister();
1586
}
1587
else
1588
{
1589
tempReg = cg->allocateRegister();
1590
tempReg->setPinningArrayPointer(node->getSymbolReference()->getSymbol()->castToInternalPointerAutoSymbol()->getPinningArrayPointer());
1591
tempReg->setContainsInternalPointer();
1592
}
1593
1594
TR::LabelSymbol *startLabel = generateLabelSymbol(cg);
1595
TR::LabelSymbol *endLabel = generateLabelSymbol(cg);
1596
startLabel->setStartInternalControlFlow();
1597
endLabel->setEndInternalControlFlow();
1598
1599
TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 7, cg->trMemory());
1600
deps->addPostCondition(tempReg, TR::RealRegister::NoReg);
1601
deps->addPostCondition(locationReg, TR::RealRegister::gr4); //TR_softwareReadBarrier helper needs this in gr4.
1602
deps->addPostCondition(evacuateReg, TR::RealRegister::NoReg);
1603
deps->addPostCondition(r3Reg, TR::RealRegister::gr3);
1604
deps->addPostCondition(r11Reg, TR::RealRegister::gr11);
1605
deps->addPostCondition(metaReg, TR::RealRegister::NoReg);
1606
deps->addPostCondition(condReg, TR::RealRegister::NoReg);
1607
1608
node->setRegister(tempReg);
1609
1610
TR::LoadStoreHandler::generateComputeAddressSequence(cg, locationReg, node);
1611
1612
generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, tempReg, TR::MemoryReference::createWithDisplacement(cg, locationReg, 0, TR::Compiler->om.sizeofReferenceAddress()));
1613
1614
if (node->getSymbolReference() == comp->getSymRefTab()->findVftSymbolRef())
1615
TR::TreeEvaluator::generateVFTMaskInstruction(cg, node, tempReg);
1616
1617
generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);
1618
1619
generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, evacuateReg,
1620
TR::MemoryReference::createWithDisplacement(cg, metaReg, comp->fej9()->thisThreadGetEvacuateBaseAddressOffset(), TR::Compiler->om.sizeofReferenceAddress()));
1621
generateTrg1Src2Instruction(cg, TR::InstOpCode::Op_cmpl, node, condReg, tempReg, evacuateReg);
1622
generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, endLabel, condReg);
1623
1624
generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, evacuateReg,
1625
TR::MemoryReference::createWithDisplacement(cg, metaReg, comp->fej9()->thisThreadGetEvacuateTopAddressOffset(), TR::Compiler->om.sizeofReferenceAddress()));
1626
generateTrg1Src2Instruction(cg, TR::InstOpCode::Op_cmpl, node, condReg, tempReg, evacuateReg);
1627
generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, endLabel, condReg);
1628
1629
// TR_softwareReadBarrier helper expects the vmThread in r3.
1630
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, r3Reg, metaReg);
1631
1632
TR::SymbolReference *helperSym = comp->getSymRefTab()->findOrCreateRuntimeHelper(TR_softwareReadBarrier);
1633
generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)helperSym->getMethodAddress(), deps, helperSym);
1634
1635
generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, tempReg, TR::MemoryReference::createWithDisplacement(cg, locationReg, 0, TR::Compiler->om.sizeofReferenceAddress()));
1636
1637
if (node->getSymbolReference() == comp->getSymRefTab()->findVftSymbolRef())
1638
TR::TreeEvaluator::generateVFTMaskInstruction(cg, node, tempReg);
1639
1640
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, endLabel, deps);
1641
1642
// TODO: Allow this to be patched or skipped at runtime for unresolved symrefs
1643
if (node->getSymbol()->isSyncVolatile() && comp->target().isSMP())
1644
{
1645
generateInstruction(cg, comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P7) ? TR::InstOpCode::lwsync : TR::InstOpCode::isync, node);
1646
}
1647
1648
cg->stopUsingRegister(evacuateReg);
1649
cg->stopUsingRegister(locationReg);
1650
cg->stopUsingRegister(r3Reg);
1651
cg->stopUsingRegister(r11Reg);
1652
cg->stopUsingRegister(condReg);
1653
1654
cg->machine()->setLinkRegisterKilled(true);
1655
1656
return tempReg;
1657
#endif
1658
}
1659
1660
TR::Register *J9::Power::TreeEvaluator::fwrtbarEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1661
{
1662
// For rdbar and wrtbar nodes we first evaluate the children we need to
1663
// handle the side effects. Then we delegate the evaluation of the remaining
1664
// children and the load/store operation to the appropriate load/store evaluator.
1665
TR::Node *sideEffectNode = node->getSecondChild();
1666
TR::Register *valueReg = cg->evaluate(node->getFirstChild());
1667
TR::Register *sideEffectRegister = cg->evaluate(sideEffectNode);
1668
if (cg->comp()->getOption(TR_EnableFieldWatch))
1669
{
1670
TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg);
1671
}
1672
// The Value Node, or the second child is not decremented here. The store evaluator also uses it, and decrements it.
1673
cg->decReferenceCount(sideEffectNode);
1674
return TR::TreeEvaluator::fstoreEvaluator(node, cg);
1675
}
1676
1677
TR::Register *J9::Power::TreeEvaluator::fwrtbariEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1678
{
1679
// For rdbar and wrtbar nodes we first evaluate the children we need to
1680
// handle the side effects. Then we delegate the evaluation of the remaining
1681
// children and the load/store operation to the appropriate load/store evaluator.
1682
TR::Node *sideEffectNode = node->getThirdChild();
1683
TR::Register *valueReg = cg->evaluate(node->getSecondChild());
1684
TR::Register *sideEffectRegister = cg->evaluate(sideEffectNode);
1685
if (cg->comp()->getOption(TR_EnableFieldWatch))
1686
{
1687
TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg);
1688
}
1689
// The Value Node, or the second child is not decremented here. The store evaluator also uses it, and decrements it.
1690
cg->decReferenceCount(sideEffectNode);
1691
return TR::TreeEvaluator::fstoreEvaluator(node, cg);
1692
}
1693
1694
TR::Register *J9::Power::TreeEvaluator::dwrtbarEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1695
{
1696
// For rdbar and wrtbar nodes we first evaluate the children we need to
1697
// handle the side effects. Then we delegate the evaluation of the remaining
1698
// children and the load/store operation to the appropriate load/store evaluator.
1699
TR::Node *sideEffectNode = node->getSecondChild();
1700
TR::Register *valueReg = cg->evaluate(node->getFirstChild());
1701
TR::Register *sideEffectRegister = cg->evaluate(node->getSecondChild());
1702
if (cg->comp()->getOption(TR_EnableFieldWatch))
1703
{
1704
TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg);
1705
}
1706
// The Value Node, or the second child is not decremented here. The store evaluator also uses it, and decrements it.
1707
cg->decReferenceCount(sideEffectNode);
1708
return TR::TreeEvaluator::dstoreEvaluator(node, cg);
1709
}
1710
1711
TR::Register *J9::Power::TreeEvaluator::dwrtbariEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1712
{
1713
// For rdbar and wrtbar nodes we first evaluate the children we need to
1714
// handle the side effects. Then we delegate the evaluation of the remaining
1715
// children and the load/store operation to the appropriate load/store evaluator.
1716
TR::Node *sideEffectNode = node->getThirdChild();
1717
TR::Register *valueReg = cg->evaluate(node->getSecondChild());
1718
TR::Register *sideEffectRegister = cg->evaluate(node->getThirdChild());
1719
if (cg->comp()->getOption(TR_EnableFieldWatch))
1720
{
1721
TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, valueReg);
1722
}
1723
// The Value Node, or the second child is not decremented here. The store evaluator also uses it, and decrements it.
1724
cg->decReferenceCount(sideEffectNode);
1725
return TR::TreeEvaluator::dstoreEvaluator(node, cg);
1726
}
1727
1728
TR::Register *J9::Power::TreeEvaluator::irdbarEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1729
{
1730
// For rdbar and wrtbar nodes we first evaluate the children we need to
1731
// handle the side effects. Then we delegate the evaluation of the remaining
1732
// children and the load/store operation to the appropriate load/store evaluator.
1733
TR::Node *sideEffectNode = node->getFirstChild();
1734
TR::Register * sideEffectRegister = cg->evaluate(sideEffectNode);
1735
if (cg->comp()->getOption(TR_EnableFieldWatch))
1736
{
1737
TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, NULL);
1738
}
1739
cg->decReferenceCount(sideEffectNode);
1740
return TR::TreeEvaluator::iloadEvaluator(node, cg);
1741
}
1742
1743
TR::Register *J9::Power::TreeEvaluator::irdbariEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1744
{
1745
// For rdbar and wrtbar nodes we first evaluate the children we need to
1746
// handle the side effects. Then we delegate the evaluation of the remaining
1747
// children and the load/store operation to the appropriate load/store evaluator.
1748
TR::Node *sideEffectNode = node->getFirstChild();
1749
TR::Register *sideEffectRegister = cg->evaluate(sideEffectNode);
1750
if (cg->comp()->getOption(TR_EnableFieldWatch))
1751
{
1752
TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, NULL);
1753
}
1754
1755
// Note: For indirect rdbar nodes, the first child (sideEffectNode) is also used by the
1756
// load evaluator. The load evaluator will also evaluate+decrement it. In order to avoid double
1757
// decrementing the node we skip doing it here and let the load evaluator do it.
1758
if (TR::Compiler->om.readBarrierType() != gc_modron_readbar_none &&
1759
cg->comp()->useCompressedPointers() &&
1760
(node->getOpCode().hasSymbolReference() &&
1761
node->getSymbolReference()->getSymbol()->getDataType() == TR::Address))
1762
{
1763
return iGenerateSoftwareReadBarrier(node, cg);
1764
}
1765
else
1766
return TR::TreeEvaluator::iloadEvaluator(node, cg);
1767
}
1768
1769
TR::Register *J9::Power::TreeEvaluator::ardbarEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1770
{
1771
// For rdbar and wrtbar nodes we first evaluate the children we need to
1772
// handle the side effects. Then we delegate the evaluation of the remaining
1773
// children and the load/store operation to the appropriate load/store evaluator.
1774
TR::Node *sideEffectNode = node->getFirstChild();
1775
TR::Register *sideEffectRegister = cg->evaluate(sideEffectNode);
1776
if (cg->comp()->getOption(TR_EnableFieldWatch))
1777
{
1778
TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, NULL);
1779
}
1780
cg->decReferenceCount(sideEffectNode);
1781
return TR::TreeEvaluator::aloadEvaluator(node, cg);
1782
}
1783
1784
TR::Register *J9::Power::TreeEvaluator::ardbariEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1785
{
1786
// For rdbar and wrtbar nodes we first evaluate the children we need to
1787
// handle the side effects. Then we delegate the evaluation of the remaining
1788
// children and the load/store operation to the appropriate load/store evaluator.
1789
TR::Register *sideEffectRegister = cg->evaluate(node->getFirstChild());
1790
if (cg->comp()->getOption(TR_EnableFieldWatch))
1791
{
1792
TR::TreeEvaluator::rdWrtbarHelperForFieldWatch(node, cg, sideEffectRegister, NULL);
1793
}
1794
// Note: For indirect rdbar nodes, the first child (sideEffectNode) is also used by the
1795
// load evaluator. The load evaluator will also evaluate+decrement it. In order to avoid double
1796
// decrementing the node we skip doing it here and let the load evaluator do it.
1797
if (TR::Compiler->om.readBarrierType() == gc_modron_readbar_none)
1798
return TR::TreeEvaluator::aloadEvaluator(node, cg);
1799
else
1800
return aGenerateSoftwareReadBarrier(node, cg);
1801
}
1802
1803
TR::Register *J9::Power::TreeEvaluator::monentEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1804
{
1805
return TR::TreeEvaluator::VMmonentEvaluator(node, cg);
1806
}
1807
1808
TR::Register *J9::Power::TreeEvaluator::monexitEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1809
{
1810
return TR::TreeEvaluator::VMmonexitEvaluator(node, cg);
1811
}
1812
1813
TR::Register *J9::Power::TreeEvaluator::asynccheckEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1814
{
1815
// The child contains an inline test. If it succeeds, the helper is called
1816
// or (with TR_ASYNC_CHECK_TRAPS) trap handler is invoked.
1817
// The address of the helper is contained as an int in this node.
1818
//
1819
TR::Compilation *comp = cg->comp();
1820
TR::Node *testNode = node->getFirstChild();
1821
TR::Node *firstChild = testNode->getFirstChild();
1822
TR::Register *src1Reg = cg->evaluate(firstChild);
1823
TR::Node *secondChild = testNode->getSecondChild();
1824
1825
TR_ASSERT(testNode->getOpCodeValue() == (comp->target().is64Bit() ? TR::lcmpeq : TR::icmpeq), "asynccheck bad format");
1826
TR_ASSERT(secondChild->getOpCode().isLoadConst() && secondChild->getRegister() == NULL, "asynccheck bad format");
1827
1828
TR::Instruction *gcPoint;
1829
1830
#if defined(TR_ASYNC_CHECK_TRAPS)
1831
if (cg->getHasResumableTrapHandler())
1832
{
1833
if (comp->target().is64Bit())
1834
{
1835
TR_ASSERT(secondChild->getLongInt() == -1L, "asynccheck bad format");
1836
gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::tdeqi, node, src1Reg, secondChild->getLongInt());
1837
}
1838
else
1839
{
1840
TR_ASSERT(secondChild->getInt() == -1, "asynccheck bad format");
1841
gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::tweqi, node, src1Reg, secondChild->getInt());
1842
}
1843
cg->setCanExceptByTrap();
1844
}
1845
else
1846
#endif
1847
{
1848
TR::Register *condReg = cg->allocateRegister(TR_CCR);
1849
if (comp->target().is64Bit())
1850
{
1851
TR_ASSERT(secondChild->getLongInt() == -1L, "asynccheck bad format");
1852
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi8, node, condReg, src1Reg, secondChild->getLongInt());
1853
}
1854
else
1855
{
1856
TR_ASSERT(secondChild->getInt() == -1, "asynccheck bad format");
1857
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, condReg, src1Reg, secondChild->getInt());
1858
}
1859
1860
TR::LabelSymbol *snippetLabel;
1861
TR::Register *jumpRegister = cg->allocateRegister();
1862
TR::RegisterDependencyConditions *dependencies = createConditionsAndPopulateVSXDeps(cg, 2);
1863
1864
snippetLabel = cg->lookUpSnippet(TR::Snippet::IsHelperCall, node->getSymbolReference());
1865
if (snippetLabel == NULL)
1866
{
1867
snippetLabel = generateLabelSymbol(cg);
1868
cg->addSnippet(new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference()));
1869
}
1870
TR::addDependency(dependencies, jumpRegister, TR::RealRegister::gr11, TR_GPR, cg);
1871
TR::addDependency(dependencies, condReg, TR::RealRegister::cr7, TR_CCR, cg);
1872
gcPoint = generateDepConditionalBranchInstruction(cg, TR::InstOpCode::beql, PPCOpProp_BranchUnlikely, node, snippetLabel, condReg, dependencies);
1873
gcPoint->setAsyncBranch();
1874
cg->machine()->setLinkRegisterKilled(true);
1875
1876
dependencies->stopUsingDepRegs(cg);
1877
}
1878
1879
gcPoint->PPCNeedsGCMap(0xFFFFFFFF);
1880
cg->decReferenceCount(firstChild);
1881
cg->decReferenceCount(secondChild);
1882
cg->decReferenceCount(testNode);
1883
return NULL;
1884
}
1885
1886
TR::Register *J9::Power::TreeEvaluator::instanceofEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1887
{
1888
return VMinstanceOfEvaluator(node, cg);
1889
}
1890
1891
TR::Register *J9::Power::TreeEvaluator::checkcastEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1892
{
1893
return TR::TreeEvaluator::VMcheckcastEvaluator(node, cg);
1894
}
1895
1896
TR::Register *J9::Power::TreeEvaluator::checkcastAndNULLCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1897
{
1898
return checkcastEvaluator(node, cg);
1899
}
1900
1901
TR::Register *J9::Power::TreeEvaluator::newObjectEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1902
{
1903
TR::Compilation* comp = cg->comp();
1904
if (comp->suppressAllocationInlining() ||
1905
TR::TreeEvaluator::requireHelperCallValueTypeAllocation(node, cg))
1906
{
1907
TR::ILOpCodes opCode = node->getOpCodeValue();
1908
TR::Node::recreate(node, TR::acall);
1909
TR::Register *targetRegister = directCallEvaluator(node, cg);
1910
TR::Node::recreate(node, opCode);
1911
return targetRegister;
1912
}
1913
else
1914
return TR::TreeEvaluator::VMnewEvaluator(node, cg);
1915
}
1916
1917
TR::Register *J9::Power::TreeEvaluator::newArrayEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1918
{
1919
if (cg->comp()->suppressAllocationInlining())
1920
{
1921
TR::ILOpCodes opCode = node->getOpCodeValue();
1922
TR::Node::recreate(node, TR::acall);
1923
TR::Register *targetRegister = directCallEvaluator(node, cg);
1924
TR::Node::recreate(node, opCode);
1925
return targetRegister;
1926
}
1927
else
1928
return TR::TreeEvaluator::VMnewEvaluator(node, cg);
1929
}
1930
1931
TR::Register *J9::Power::TreeEvaluator::anewArrayEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1932
{
1933
if (cg->comp()->suppressAllocationInlining())
1934
{
1935
TR::ILOpCodes opCode = node->getOpCodeValue();
1936
TR::Node::recreate(node, TR::acall);
1937
TR::Register *targetRegister = directCallEvaluator(node, cg);
1938
TR::Node::recreate(node, opCode);
1939
return targetRegister;
1940
}
1941
else
1942
return TR::TreeEvaluator::VMnewEvaluator(node, cg);
1943
}
1944
1945
TR::Register *J9::Power::TreeEvaluator::multianewArrayEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1946
{
1947
TR::ILOpCodes opCode = node->getOpCodeValue();
1948
TR::Node::recreate(node, TR::acall);
1949
TR::Register *targetRegister = directCallEvaluator(node, cg);
1950
TR::Node::recreate(node, opCode);
1951
return targetRegister;
1952
}
1953
1954
TR::Register *J9::Power::TreeEvaluator::arraylengthEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1955
{
1956
TR_ASSERT(cg->comp()->requiresSpineChecks(), "TR::arraylength should be lowered when hybrid arraylets are not in use");
1957
TR_ASSERT(node->getOpCodeValue() == TR::arraylength, "arraylengthEvaluator expecting TR::arraylength");
1958
1959
TR::Register *objectReg = cg->evaluate(node->getFirstChild());
1960
TR::Register *lengthReg = cg->allocateRegister();
1961
TR::Register *condReg = cg->allocateRegister(TR_CCR);
1962
TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);
1963
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
1964
1965
TR::MemoryReference *contiguousArraySizeMR = TR::MemoryReference::createWithDisplacement(cg, objectReg, fej9->getOffsetOfContiguousArraySizeField(), 4);
1966
TR::MemoryReference *discontiguousArraySizeMR = TR::MemoryReference::createWithDisplacement(cg, objectReg, fej9->getOffsetOfDiscontiguousArraySizeField(), 4);
1967
1968
TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 3, cg->trMemory());
1969
deps->addPostCondition(objectReg, TR::RealRegister::NoReg);
1970
deps->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0();
1971
deps->addPostCondition(lengthReg, TR::RealRegister::NoReg);
1972
deps->addPostCondition(condReg, TR::RealRegister::NoReg);
1973
1974
// lwz R, [B + contiguousSize] ; Load contiguous array length
1975
// cmp R, 0 ; If 0, must be a discontiguous array
1976
// beq out-of-line
1977
// done:
1978
//
1979
// out-of-line:
1980
// lwz R, [B + discontiguousSize] ; Load discontiguous array length
1981
// b done
1982
1983
TR::LabelSymbol *discontiguousArrayLabel = generateLabelSymbol(cg);
1984
TR_PPCOutOfLineCodeSection *discontiguousArrayOOL = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(discontiguousArrayLabel, doneLabel, cg);
1985
cg->getPPCOutOfLineCodeSectionList().push_front(discontiguousArrayOOL);
1986
1987
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, lengthReg, contiguousArraySizeMR);
1988
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, condReg, lengthReg, 0);
1989
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, PPCOpProp_BranchUnlikely, node, discontiguousArrayLabel, condReg);
1990
generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel);
1991
1992
// OOL begin.
1993
//
1994
discontiguousArrayOOL->swapInstructionListsWithCompilation();
1995
{
1996
generateLabelInstruction(cg, TR::InstOpCode::label, node, discontiguousArrayLabel);
1997
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, lengthReg, discontiguousArraySizeMR);
1998
generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);
1999
}
2000
discontiguousArrayOOL->swapInstructionListsWithCompilation();
2001
//
2002
// OOL end.
2003
2004
TR::LabelSymbol *depLabel = generateLabelSymbol(cg);
2005
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, depLabel, deps);
2006
2007
cg->stopUsingRegister(condReg);
2008
cg->decReferenceCount(node->getFirstChild());
2009
node->setRegister(lengthReg);
2010
2011
return lengthReg;
2012
}
2013
2014
TR::Register *J9::Power::TreeEvaluator::DIVCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)
2015
{
2016
TR::Compilation *comp = cg->comp();
2017
TR::Node *secondChild = node->getFirstChild()->getSecondChild();
2018
TR::DataType type = secondChild->getType();
2019
TR::Register *srcReg;
2020
TR::Instruction *gcPoint;
2021
bool constDivisor = secondChild->getOpCode().isLoadConst();
2022
bool killSrc = false;
2023
2024
if (!constDivisor || (type.isInt32() && secondChild->getInt() == 0) || (type.isInt64() && secondChild->getLongInt() == 0))
2025
{
2026
if (!constDivisor || cg->getHasResumableTrapHandler())
2027
{
2028
srcReg = cg->evaluate(secondChild);
2029
if (type.isInt64() && comp->target().is32Bit())
2030
{
2031
TR::Register *trgReg = cg->allocateRegister();
2032
generateTrg1Src2Instruction(cg, TR::InstOpCode::OR, node, trgReg, srcReg->getHighOrder(), srcReg->getLowOrder());
2033
srcReg = trgReg;
2034
killSrc = true;
2035
}
2036
}
2037
2038
if (cg->getHasResumableTrapHandler())
2039
{
2040
if (type.isInt64() && comp->target().is64Bit())
2041
gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::tdllti, node, srcReg, 1);
2042
else
2043
gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::twllti, node, srcReg, 1);
2044
cg->setCanExceptByTrap();
2045
}
2046
else
2047
{
2048
TR::LabelSymbol *snippetLabel = cg->lookUpSnippet(TR::Snippet::IsHelperCall, node->getSymbolReference());
2049
TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(1, 1, cg->trMemory());
2050
TR::Register *jumpReg = cg->allocateRegister();
2051
2052
if (snippetLabel == NULL)
2053
{
2054
snippetLabel = generateLabelSymbol(cg);
2055
cg->addSnippet(new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference()));
2056
}
2057
2058
// trampoline kills gr11
2059
TR::addDependency(conditions, jumpReg, TR::RealRegister::gr11, TR_GPR, cg);
2060
if (constDivisor)
2061
{
2062
// Can be improved to: call the helper directly.
2063
gcPoint = generateDepLabelInstruction(cg, TR::InstOpCode::bl, node, snippetLabel, conditions);
2064
}
2065
else
2066
{
2067
TR::Register *condReg = cg->allocateRegister(TR_CCR);
2068
if (type.isInt64() && comp->target().is64Bit())
2069
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli8, node, condReg, srcReg, 0);
2070
else
2071
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, condReg, srcReg, 0);
2072
gcPoint = generateDepConditionalBranchInstruction(cg, TR::InstOpCode::beql, PPCOpProp_BranchUnlikely, node, snippetLabel, condReg, conditions);
2073
cg->stopUsingRegister(condReg);
2074
}
2075
cg->stopUsingRegister(jumpReg);
2076
}
2077
2078
if (killSrc)
2079
cg->stopUsingRegister(srcReg);
2080
2081
gcPoint->PPCNeedsGCMap(0xFFFFFFFF);
2082
}
2083
2084
cg->evaluate(node->getFirstChild());
2085
cg->decReferenceCount(node->getFirstChild());
2086
return NULL;
2087
}
2088
2089
static void genBoundCheck(TR::CodeGenerator *cg, TR::Node *node, TR::Register *indexReg, int32_t indexVal, TR::Register *arrayLengthReg, int32_t arrayLengthVal,
2090
TR::Register *condReg, bool noTrap)
2091
{
2092
TR::Instruction *gcPoint;
2093
if (noTrap)
2094
{
2095
TR::LabelSymbol *boundCheckFailSnippetLabel = cg->lookUpSnippet(TR::Snippet::IsHelperCall, node->getSymbolReference());
2096
if (!boundCheckFailSnippetLabel)
2097
{
2098
boundCheckFailSnippetLabel = generateLabelSymbol(cg);
2099
cg->addSnippet(new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, boundCheckFailSnippetLabel, node->getSymbolReference()));
2100
}
2101
2102
if (indexReg)
2103
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmpl4, node, condReg, arrayLengthReg, indexReg);
2104
else
2105
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, condReg, arrayLengthReg, indexVal);
2106
2107
// NOTE: Trampoline kills gr11
2108
gcPoint = generateConditionalBranchInstruction(cg, TR::InstOpCode::blel, PPCOpProp_BranchUnlikely, node, boundCheckFailSnippetLabel, condReg);
2109
}
2110
else
2111
{
2112
if (indexReg)
2113
{
2114
if (arrayLengthReg)
2115
gcPoint = generateSrc2Instruction(cg, TR::InstOpCode::twlle, node, arrayLengthReg, indexReg);
2116
else
2117
gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::twlgei, node, indexReg, arrayLengthVal);
2118
}
2119
else
2120
{
2121
if (arrayLengthReg)
2122
gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::twllei, node, arrayLengthReg, indexVal);
2123
else if (arrayLengthVal <= indexVal)
2124
gcPoint = generateInstruction(cg, TR::InstOpCode::trap, node);
2125
}
2126
2127
cg->setCanExceptByTrap();
2128
}
2129
2130
// Exception edges don't have any live regs
2131
gcPoint->PPCNeedsGCMap(0);
2132
}
2133
2134
TR::Register *J9::Power::TreeEvaluator::BNDCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)
2135
{
2136
static bool noReversedTrap = (feGetEnv("TR_noReversedTrap") != NULL);
2137
TR::Node *secondChild = node->getSecondChild();
2138
TR::Node *firstChild = node->getFirstChild();
2139
TR::Register *src1Reg;
2140
TR::Register *src2Reg = NULL;
2141
TR::Register *cndReg, *tmpReg = NULL;
2142
int32_t value;
2143
TR::RegisterDependencyConditions *conditions;
2144
TR::LabelSymbol *snippetLabel;
2145
TR::Instruction *gcPoint;
2146
bool noTrap = !cg->getHasResumableTrapHandler();
2147
bool reversed = false;
2148
2149
if (noTrap)
2150
{
2151
cndReg = cg->allocateRegister(TR_CCR);
2152
conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(4, 4, cg->trMemory());
2153
}
2154
2155
if (firstChild->getOpCode().isLoadConst() && firstChild->getInt() >= 0 && firstChild->getInt() <= UPPER_IMMED && firstChild->getRegister() == NULL && !noReversedTrap)
2156
{
2157
src2Reg = cg->evaluate(secondChild);
2158
reversed = true;
2159
}
2160
else
2161
{
2162
src1Reg = cg->evaluate(firstChild);
2163
2164
if (secondChild->getOpCode().isLoadConst() && secondChild->getRegister() == NULL)
2165
{
2166
value = secondChild->getInt();
2167
if (value < 0 || value > UPPER_IMMED)
2168
{
2169
src2Reg = cg->evaluate(secondChild);
2170
}
2171
}
2172
else
2173
src2Reg = cg->evaluate(secondChild);
2174
}
2175
2176
if (!noTrap)
2177
{
2178
if (reversed)
2179
{
2180
gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::twlgei, node, src2Reg, firstChild->getInt());
2181
}
2182
else
2183
{
2184
if (src2Reg == NULL)
2185
gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::twllei, node, src1Reg, value);
2186
else
2187
gcPoint = generateSrc2Instruction(cg, TR::InstOpCode::twlle, node, src1Reg, src2Reg);
2188
}
2189
}
2190
else
2191
{
2192
if (reversed)
2193
{
2194
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, cndReg, src2Reg, firstChild->getInt());
2195
}
2196
else
2197
{
2198
if (src2Reg == NULL)
2199
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, cndReg, src1Reg, value);
2200
else
2201
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmpl4, node, cndReg, src1Reg, src2Reg);
2202
}
2203
2204
snippetLabel = cg->lookUpSnippet(TR::Snippet::IsHelperCall, node->getSymbolReference());
2205
if (snippetLabel == NULL)
2206
{
2207
snippetLabel = generateLabelSymbol(cg);
2208
cg->addSnippet(new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference()));
2209
}
2210
2211
tmpReg = cg->allocateRegister();
2212
// trampoline kills gr11
2213
TR::addDependency(conditions, tmpReg, TR::RealRegister::gr11, TR_GPR, cg);
2214
gcPoint = generateDepConditionalBranchInstruction(cg, reversed ? TR::InstOpCode::bgel : TR::InstOpCode::blel, PPCOpProp_BranchUnlikely, node, snippetLabel, cndReg, conditions);
2215
cg->stopUsingRegister(tmpReg);
2216
}
2217
2218
if (noTrap)
2219
cg->stopUsingRegister(cndReg);
2220
2221
gcPoint->PPCNeedsGCMap(0xFFFFFFFF);
2222
if (!noTrap)
2223
cg->setCanExceptByTrap();
2224
cg->decReferenceCount(firstChild);
2225
cg->decReferenceCount(secondChild);
2226
secondChild->setIsNonNegative(true);
2227
return (NULL);
2228
}
2229
2230
TR::Register *J9::Power::TreeEvaluator::ArrayCopyBNDCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)
2231
{
2232
TR::Node *firstChild = node->getFirstChild();
2233
TR::Node *secondChild = node->getSecondChild();
2234
TR::LabelSymbol *snippetLabel = NULL;
2235
TR::Instruction *gcPoint;
2236
bool noTrap = !cg->getHasResumableTrapHandler();
2237
bool directCase = firstChild->getOpCode().isLoadConst() && secondChild->getOpCode().isLoadConst() && firstChild->getInt() < secondChild->getInt();
2238
2239
if (directCase || noTrap)
2240
{
2241
snippetLabel = cg->lookUpSnippet(TR::Snippet::IsHelperCall, node->getSymbolReference());
2242
if (snippetLabel == NULL)
2243
{
2244
snippetLabel = generateLabelSymbol(cg);
2245
cg->addSnippet(new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference()));
2246
}
2247
}
2248
2249
// We are checking for firstChild>=secondChild. We don't need to copy registers.
2250
2251
if (directCase)
2252
{
2253
gcPoint = generateLabelInstruction(cg, TR::InstOpCode::bl, node, snippetLabel);
2254
}
2255
else if (firstChild->getOpCode().isLoadConst() && firstChild->getInt() >= LOWER_IMMED && firstChild->getInt() <= UPPER_IMMED && firstChild->getRegister() == NULL)
2256
{
2257
TR::Register *copyIndexReg = cg->evaluate(secondChild);
2258
if (noTrap)
2259
{
2260
TR::Register *cndReg = cg->allocateRegister(TR_CCR);
2261
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, cndReg, copyIndexReg, firstChild->getInt());
2262
gcPoint = generateConditionalBranchInstruction(cg, TR::InstOpCode::bgtl, PPCOpProp_BranchUnlikely, node, snippetLabel, cndReg);
2263
cg->stopUsingRegister(cndReg);
2264
}
2265
else
2266
{
2267
gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::twgti, node, copyIndexReg, firstChild->getInt());
2268
cg->setCanExceptByTrap();
2269
}
2270
}
2271
else
2272
{
2273
TR::Register *boundReg = cg->evaluate(firstChild);
2274
if (secondChild->getOpCode().isLoadConst() && secondChild->getInt() >= LOWER_IMMED && secondChild->getInt() <= UPPER_IMMED)
2275
{
2276
if (noTrap)
2277
{
2278
TR::Register *cndReg = cg->allocateRegister(TR_CCR);
2279
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, cndReg, boundReg, secondChild->getInt());
2280
gcPoint = generateConditionalBranchInstruction(cg, TR::InstOpCode::bltl, PPCOpProp_BranchUnlikely, node, snippetLabel, cndReg);
2281
cg->stopUsingRegister(cndReg);
2282
}
2283
else
2284
{
2285
gcPoint = generateSrc1Instruction(cg, TR::InstOpCode::twlti, node, boundReg, secondChild->getInt());
2286
cg->setCanExceptByTrap();
2287
}
2288
}
2289
else
2290
{
2291
TR::Register *copyIndexReg = cg->evaluate(secondChild);
2292
if (noTrap)
2293
{
2294
TR::Register *cndReg = cg->allocateRegister(TR_CCR);
2295
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, cndReg, boundReg, copyIndexReg);
2296
gcPoint = generateConditionalBranchInstruction(cg, TR::InstOpCode::bltl, PPCOpProp_BranchUnlikely, node, snippetLabel, cndReg);
2297
cg->stopUsingRegister(cndReg);
2298
}
2299
else
2300
{
2301
gcPoint = generateSrc2Instruction(cg, TR::InstOpCode::twlt, node, boundReg, copyIndexReg);
2302
cg->setCanExceptByTrap();
2303
}
2304
}
2305
}
2306
2307
gcPoint->PPCNeedsGCMap(0xFFFFFFFF);
2308
cg->decReferenceCount(firstChild);
2309
cg->decReferenceCount(secondChild);
2310
if (secondChild->getOpCode().isLoadConst() && secondChild->getInt() >= 0)
2311
firstChild->setIsNonNegative(true);
2312
return (NULL);
2313
}
2314
2315
static TR::Instruction* genSpineCheck(TR::CodeGenerator *cg, TR::Node *node, TR::Register *arrayLengthReg, TR::Register *condReg, TR::LabelSymbol *discontiguousArrayLabel)
2316
{
2317
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, condReg, arrayLengthReg, 0);
2318
return generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, discontiguousArrayLabel, condReg);
2319
}
2320
2321
static TR::Instruction* genSpineCheck(TR::CodeGenerator *cg, TR::Node *node, TR::Register *baseArrayReg, TR::Register *arrayLengthReg, TR::Register *condReg,
2322
TR::LabelSymbol *discontiguousArrayLabel)
2323
{
2324
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
2325
TR::MemoryReference *contiguousArraySizeMR = TR::MemoryReference::createWithDisplacement(cg, baseArrayReg, fej9->getOffsetOfContiguousArraySizeField(), 4);
2326
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, arrayLengthReg, contiguousArraySizeMR);
2327
return genSpineCheck(cg, node, arrayLengthReg, condReg, discontiguousArrayLabel);
2328
}
2329
2330
static void genArrayletAccessAddr(TR::CodeGenerator *cg, TR::Node *node, int32_t elementSize,
2331
// Inputs:
2332
TR::Register *baseArrayReg, TR::Register *indexReg, int32_t indexVal,
2333
// Outputs:
2334
TR::Register *arrayletReg, TR::Register *offsetReg, int32_t& offsetVal)
2335
{
2336
TR::Compilation* comp = cg->comp();
2337
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
2338
TR_ASSERT(offsetReg || !indexReg, "Expecting valid offset reg when index reg is passed");
2339
2340
uintptr_t arrayHeaderSize = TR::Compiler->om.discontiguousArrayHeaderSizeInBytes();
2341
int32_t spinePointerSize = TR::Compiler->om.sizeofReferenceField();
2342
int32_t spinePointerSizeShift = spinePointerSize == 8 ? 3 : 2;
2343
2344
TR::MemoryReference *spineMR;
2345
2346
// Calculate the spine offset.
2347
//
2348
if (indexReg)
2349
{
2350
int32_t spineShift = fej9->getArraySpineShift(elementSize);
2351
2352
// spineOffset = (index >> spineShift) * spinePtrSize
2353
// = (index >> spineShift) << spinePtrSizeShift
2354
// = (index >> (spineShift - spinePtrSizeShift)) & ~(spinePtrSize - 1)
2355
// spineOffset += arrayHeaderSize
2356
//
2357
TR_ASSERT(spineShift >= spinePointerSizeShift, "Unexpected spine shift value");
2358
generateShiftRightLogicalImmediate(cg, node, arrayletReg, indexReg, spineShift - spinePointerSizeShift);
2359
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, arrayletReg, arrayletReg, 0, ~(spinePointerSize - 1));
2360
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, arrayletReg, arrayletReg, arrayHeaderSize);
2361
2362
spineMR = TR::MemoryReference::createWithIndexReg(cg, baseArrayReg, arrayletReg, spinePointerSize);
2363
}
2364
else
2365
{
2366
int32_t spineIndex = fej9->getArrayletLeafIndex(indexVal, elementSize);
2367
int32_t spineDisp32 = spineIndex * spinePointerSize + arrayHeaderSize;
2368
2369
spineMR = TR::MemoryReference::createWithDisplacement(cg, baseArrayReg, spineDisp32, spinePointerSize);
2370
}
2371
2372
// Load the arraylet from the spine.
2373
//
2374
generateTrg1MemInstruction(cg, spinePointerSize == 8 ? TR::InstOpCode::ld : TR::InstOpCode::lwz, node, arrayletReg, spineMR);
2375
2376
// Calculate the arraylet offset.
2377
//
2378
if (indexReg)
2379
{
2380
int32_t arrayletMask = fej9->getArrayletMask(elementSize);
2381
int32_t elementSizeShift = CHAR_BIT * sizeof(int32_t) - leadingZeroes(elementSize - 1);
2382
2383
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, offsetReg, indexReg, elementSizeShift, arrayletMask << elementSizeShift);
2384
}
2385
else
2386
offsetVal = (fej9->getLeafElementIndex(indexVal, elementSize) * elementSize);
2387
}
2388
2389
static TR::InstOpCode::Mnemonic getLoadOrStoreFromDataType(TR::CodeGenerator *cg, TR::DataType dt, int32_t elementSize, bool isUnsigned, bool returnLoad)
2390
{
2391
switch (dt)
2392
{
2393
case TR::Int8:
2394
return returnLoad ? TR::InstOpCode::lbz : TR::InstOpCode::stb;
2395
case TR::Int16:
2396
if (returnLoad)
2397
return isUnsigned ? TR::InstOpCode::lhz : TR::InstOpCode::lha;
2398
else
2399
return TR::InstOpCode::sth;
2400
case TR::Int32:
2401
if (returnLoad)
2402
return TR::InstOpCode::lwz;
2403
else
2404
return TR::InstOpCode::stw;
2405
case TR::Int64:
2406
return returnLoad ? TR::InstOpCode::ld : TR::InstOpCode::std;
2407
case TR::Float:
2408
return returnLoad ? TR::InstOpCode::lfs : TR::InstOpCode::stfs;
2409
case TR::Double:
2410
return returnLoad ? TR::InstOpCode::lfd : TR::InstOpCode::stfd;
2411
case TR::Address:
2412
if (returnLoad)
2413
return elementSize == 8 ? TR::InstOpCode::ld : TR::InstOpCode::lwz;
2414
else
2415
return elementSize == 8 ? TR::InstOpCode::std : TR::InstOpCode::stw;
2416
default:
2417
TR_ASSERT(false, "Unexpected array data type");
2418
return TR::InstOpCode::bad;
2419
}
2420
}
2421
2422
static void genDecompressPointer(TR::CodeGenerator *cg, TR::Node *node, TR::Register *ptrReg, TR::Register *condReg = NULL, bool nullCheck = true)
2423
{
2424
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());
2425
int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();
2426
2427
if (shiftAmount != 0)
2428
generateShiftLeftImmediateLong(cg, node, ptrReg, ptrReg, shiftAmount);
2429
}
2430
2431
static TR::Register *addConstantToLongWithTempReg(TR::Node * node, TR::Register *srcReg, int64_t value, TR::Register *trgReg, TR::Register *tempReg, TR::CodeGenerator *cg)
2432
{
2433
if (!trgReg)
2434
trgReg = cg->allocateRegister();
2435
2436
if ((int16_t) value == value)
2437
{
2438
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, trgReg, srcReg, value);
2439
}
2440
// NOTE: the following only works if the second add's immediate is not sign extended
2441
else if (((int32_t) value == value) && ((value & 0x8000) == 0))
2442
{
2443
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addis, node, trgReg, srcReg, value >> 16);
2444
if (value & 0xffff)
2445
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, trgReg, trgReg, LO_VALUE(value));
2446
}
2447
else
2448
{
2449
loadConstant(cg, node, value, tempReg);
2450
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, trgReg, srcReg, tempReg);
2451
}
2452
2453
return trgReg;
2454
}
2455
2456
static void genDecompressPointerWithTempReg(TR::CodeGenerator *cg, TR::Node *node, TR::Register *ptrReg, TR::Register *tempReg, TR::Register *condReg = NULL, bool nullCheck = true)
2457
{
2458
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());
2459
int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();
2460
2461
if (shiftAmount != 0)
2462
generateShiftLeftImmediateLong(cg, node, ptrReg, ptrReg, shiftAmount);
2463
}
2464
2465
static TR::Register *genDecompressPointerNonNull2Regs(TR::CodeGenerator *cg, TR::Node *node, TR::Register *ptrReg, TR::Register *targetReg)
2466
{
2467
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());
2468
int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();
2469
2470
if (shiftAmount != 0)
2471
{
2472
generateShiftLeftImmediateLong(cg, node, targetReg, ptrReg, shiftAmount);
2473
return targetReg;
2474
}
2475
else
2476
{
2477
return ptrReg;
2478
}
2479
}
2480
2481
static TR::Register *genDecompressPointerNonNull2RegsWithTempReg(TR::CodeGenerator *cg, TR::Node *node, TR::Register *ptrReg, TR::Register *targetReg, TR::Register *tempReg)
2482
{
2483
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());
2484
int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();
2485
2486
if (shiftAmount != 0)
2487
{
2488
generateShiftLeftImmediateLong(cg, node, targetReg, ptrReg, shiftAmount);
2489
return targetReg;
2490
}
2491
else
2492
{
2493
return ptrReg;
2494
}
2495
}
2496
2497
static void genCompressPointerWithTempReg(TR::CodeGenerator *cg, TR::Node *node, TR::Register *ptrReg, TR::Register *tempReg, TR::Register *condReg = NULL, bool nullCheck = true)
2498
{
2499
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());
2500
int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();
2501
2502
if (shiftAmount != 0)
2503
{
2504
generateShiftRightLogicalImmediateLong(cg, node, ptrReg, ptrReg, shiftAmount);
2505
}
2506
}
2507
2508
static void genCompressPointer(TR::CodeGenerator *cg, TR::Node *node, TR::Register *ptrReg, TR::Register *condReg = NULL, bool nullCheck = true)
2509
{
2510
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());
2511
int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();
2512
2513
if (shiftAmount != 0)
2514
{
2515
generateShiftRightLogicalImmediateLong(cg, node, ptrReg, ptrReg, shiftAmount);
2516
}
2517
}
2518
2519
static TR::Register *genCompressPointerNonNull2RegsWithTempReg(TR::CodeGenerator *cg, TR::Node *node, TR::Register *ptrReg, TR::Register *targetReg, TR::Register *tempReg)
2520
{
2521
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());
2522
int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();
2523
2524
if (shiftAmount != 0)
2525
{
2526
generateShiftRightLogicalImmediateLong(cg, node, targetReg, ptrReg, shiftAmount);
2527
return targetReg;
2528
}
2529
else
2530
return ptrReg;
2531
}
2532
2533
static TR::Register *genCompressPointerNonNull2Regs(TR::CodeGenerator *cg, TR::Node *node, TR::Register *ptrReg, TR::Register *targetReg)
2534
{
2535
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());
2536
int32_t shiftAmount = TR::Compiler->om.compressedReferenceShift();
2537
2538
if (shiftAmount != 0)
2539
{
2540
generateShiftRightLogicalImmediateLong(cg, node, targetReg, ptrReg, shiftAmount);
2541
return targetReg;
2542
}
2543
else
2544
return ptrReg;
2545
}
2546
2547
// Handles both BNDCHKwithSpineCHK and SpineCHK nodes.
2548
//
2549
TR::Register *J9::Power::TreeEvaluator::BNDCHKwithSpineCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)
2550
{
2551
TR::Compilation *comp = cg->comp();
2552
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
2553
bool noTrap = !cg->getHasResumableTrapHandler();
2554
bool needsBoundCheck = node->getOpCodeValue() == TR::BNDCHKwithSpineCHK;
2555
bool needsBoundCheckOOL;
2556
2557
TR_PPCScratchRegisterManager *srm = cg->generateScratchRegisterManager();
2558
2559
TR::Node *loadOrStoreChild = node->getFirstChild();
2560
TR::Node *baseArrayChild = node->getSecondChild();
2561
TR::Node *arrayLengthChild;
2562
TR::Node *indexChild;
2563
2564
if (needsBoundCheck)
2565
{
2566
arrayLengthChild = node->getChild(2);
2567
indexChild = node->getChild(3);
2568
}
2569
else
2570
indexChild = node->getChild(2);
2571
2572
TR::Register *baseArrayReg = cg->evaluate(baseArrayChild);
2573
TR::Register *indexReg;
2574
TR::Register *loadOrStoreReg;
2575
TR::Register *arrayLengthReg;
2576
2577
// If the index is too large to be an immediate load it in a register
2578
if (!indexChild->getOpCode().isLoadConst() || (indexChild->getInt() > UPPER_IMMED || indexChild->getInt() < 0))
2579
indexReg = cg->evaluate(indexChild);
2580
else
2581
indexReg = NULL;
2582
2583
// For primitive stores anchored under the check node, we must evaluate the source node
2584
// before the bound check branch so that its available to the snippet.
2585
//
2586
if (loadOrStoreChild->getOpCode().isStore() && !loadOrStoreChild->getRegister())
2587
{
2588
TR::Node *valueChild = loadOrStoreChild->getSecondChild();
2589
cg->evaluate(valueChild);
2590
}
2591
2592
// Evaluate any escaping nodes before the OOL branch since they won't be evaluated in the OOL path.
2593
preEvaluateEscapingNodesForSpineCheck(node, cg);
2594
2595
// Label to the OOL code that will perform the load/store/agen for discontiguous arrays (and the bound check if needed).
2596
TR::LabelSymbol *discontiguousArrayLabel = generateLabelSymbol(cg);
2597
2598
// Label back to main-line that the OOL code will branch to when done.
2599
TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);
2600
doneLabel->setEndInternalControlFlow();
2601
2602
TR_PPCOutOfLineCodeSection *discontiguousArrayOOL = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(discontiguousArrayLabel, doneLabel, cg);
2603
cg->getPPCOutOfLineCodeSectionList().push_front(discontiguousArrayOOL);
2604
2605
TR::Instruction *OOLBranchInstr;
2606
2607
if (needsBoundCheck)
2608
{
2609
TR_ASSERT(arrayLengthChild, "Expecting to have an array length child for BNDCHKwithSpineCHK node");
2610
TR_ASSERT(
2611
arrayLengthChild->getOpCode().isConversion() || arrayLengthChild->getOpCodeValue() == TR::iloadi || arrayLengthChild->getOpCodeValue() == TR::iload
2612
|| arrayLengthChild->getOpCodeValue() == TR::iRegLoad || arrayLengthChild->getOpCode().isLoadConst(),
2613
"Expecting array length child under BNDCHKwithSpineCHK to be a conversion, iiload, iload, iRegLoad or iconst");
2614
2615
TR::Register *condReg = srm->findOrCreateScratchRegister(TR_CCR);
2616
2617
arrayLengthReg = arrayLengthChild->getRegister();
2618
2619
if (arrayLengthReg)
2620
{
2621
OOLBranchInstr = genSpineCheck(cg, node, baseArrayReg, arrayLengthReg, condReg, discontiguousArrayLabel);
2622
needsBoundCheckOOL = true;
2623
genBoundCheck(cg, node, indexReg, indexChild->getInt(), arrayLengthReg, arrayLengthChild->getInt(), condReg, noTrap);
2624
}
2625
else if (arrayLengthChild->getOpCode().isLoadConst())
2626
{
2627
// If the constant arraylength is non-zero then it will pass the spine check (hence its
2628
// a contiguous array) and the BNDCHK can be done inline with no OOL path.
2629
//
2630
// If the constant arraylength is zero then we will always go OOL.
2631
//
2632
// TODO: in the future there shouldn't be an OOL path because any valid access must be
2633
// on a discontiguous array.
2634
//
2635
if (arrayLengthChild->getInt() != 0)
2636
{
2637
// The array must be contiguous.
2638
//
2639
2640
// If the array length is too large to be an immediate load it in a register for the bound check
2641
if (arrayLengthChild->getInt() > UPPER_IMMED || arrayLengthChild->getInt() < 0)
2642
arrayLengthReg = cg->evaluate(arrayLengthChild);
2643
2644
// Do the bound check first.
2645
genBoundCheck(cg, node, indexReg, indexChild->getInt(), arrayLengthReg, arrayLengthChild->getInt(), condReg, noTrap);
2646
needsBoundCheckOOL = false;
2647
TR::Register *scratchArrayLengthReg = srm->findOrCreateScratchRegister();
2648
OOLBranchInstr = genSpineCheck(cg, node, baseArrayReg, scratchArrayLengthReg, condReg, discontiguousArrayLabel);
2649
srm->reclaimScratchRegister(scratchArrayLengthReg);
2650
}
2651
else
2652
{
2653
// Zero length array or discontiguous array. Unconditionally branch to the OOL path
2654
// to find out which.
2655
//
2656
OOLBranchInstr = generateLabelInstruction(cg, TR::InstOpCode::b, node, discontiguousArrayLabel);
2657
needsBoundCheckOOL = true;
2658
}
2659
}
2660
else
2661
{
2662
// Load the contiguous array length.
2663
arrayLengthReg = cg->evaluate(arrayLengthChild);
2664
// If the array length is 0, this is a discontiguous array and the bound check will be handled OOL.
2665
OOLBranchInstr = genSpineCheck(cg, node, arrayLengthReg, condReg, discontiguousArrayLabel);
2666
needsBoundCheckOOL = true;
2667
// Do the bound check using the contiguous array length.
2668
genBoundCheck(cg, node, indexReg, indexChild->getInt(), arrayLengthReg, arrayLengthChild->getInt(), condReg, noTrap);
2669
}
2670
2671
srm->reclaimScratchRegister(condReg);
2672
cg->decReferenceCount(arrayLengthChild);
2673
}
2674
else
2675
{
2676
// Spine check only; load the contiguous length, check for 0, branch OOL if discontiguous.
2677
needsBoundCheckOOL = false;
2678
2679
arrayLengthReg = srm->findOrCreateScratchRegister();
2680
2681
TR::Register *condReg = srm->findOrCreateScratchRegister(TR_CCR);
2682
2683
OOLBranchInstr = genSpineCheck(cg, node, baseArrayReg, arrayLengthReg, condReg, discontiguousArrayLabel);
2684
2685
srm->reclaimScratchRegister(arrayLengthReg);
2686
srm->reclaimScratchRegister(condReg);
2687
}
2688
2689
// For reference stores, only evaluate the array element address because the store cannot
2690
// happen here (it must be done via the array store check).
2691
//
2692
// For primitive stores, evaluate them now.
2693
// For loads, evaluate them now.
2694
// For address calculations (aladd/aiadd), evaluate them now.
2695
//
2696
bool doLoadOrStore;
2697
bool doLoadDecompress = false;
2698
bool doAddressComputation;
2699
2700
if (loadOrStoreChild->getOpCode().isStore() && loadOrStoreChild->getReferenceCount() > 1)
2701
{
2702
TR_ASSERT(loadOrStoreChild->getOpCode().isWrtBar(), "Opcode must be wrtbar");
2703
loadOrStoreReg = cg->evaluate(loadOrStoreChild->getFirstChild());
2704
cg->decReferenceCount(loadOrStoreChild->getFirstChild());
2705
doLoadOrStore = false;
2706
doAddressComputation = true;
2707
}
2708
else
2709
{
2710
// If it's a store and not commoned then it must be a primitive store.
2711
// If it's an address load it may need decompression in the OOL path.
2712
2713
// Top-level check whether a decompression sequence is necessary, because the first child
2714
// may have been created by a PRE temp.
2715
//
2716
if ((loadOrStoreChild->getOpCodeValue() == TR::aload || loadOrStoreChild->getOpCodeValue() == TR::aRegLoad) && node->isSpineCheckWithArrayElementChild() && comp->target().is64Bit()
2717
&& comp->useCompressedPointers())
2718
{
2719
doLoadDecompress = true;
2720
}
2721
2722
TR::Node *actualLoadOrStoreChild = loadOrStoreChild;
2723
while (actualLoadOrStoreChild->getOpCode().isConversion() || actualLoadOrStoreChild->containsCompressionSequence())
2724
{
2725
if (actualLoadOrStoreChild->containsCompressionSequence())
2726
doLoadDecompress = true;
2727
actualLoadOrStoreChild = actualLoadOrStoreChild->getFirstChild();
2728
}
2729
2730
doLoadOrStore = actualLoadOrStoreChild->getOpCode().hasSymbolReference()
2731
&& (actualLoadOrStoreChild->getSymbolReference()->getSymbol()->isArrayShadowSymbol()
2732
|| actualLoadOrStoreChild->getSymbolReference()->getSymbol()->isArrayletShadowSymbol()) && node->isSpineCheckWithArrayElementChild();
2733
2734
// If the 1st child is not a load/store/aladd/aiadd it's probably a nop (e.g. const) at this point due to commoning
2735
//
2736
doAddressComputation = !doLoadOrStore && actualLoadOrStoreChild->getOpCode().isArrayRef() && !node->isSpineCheckWithArrayElementChild();
2737
2738
if (doLoadOrStore || doAddressComputation || !loadOrStoreChild->getOpCode().isLoadConst())
2739
loadOrStoreReg = cg->evaluate(loadOrStoreChild);
2740
else
2741
loadOrStoreReg = NULL;
2742
}
2743
2744
if (noTrap)
2745
{
2746
TR::RegisterDependencyConditions *mainlineDeps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 1, cg->trMemory());
2747
// Trampoline to bound check fail kills gr11
2748
// TODO: Try to use this as the arraylet reg
2749
TR::Register *gr11 = cg->allocateRegister();
2750
mainlineDeps->addPostCondition(gr11, TR::RealRegister::gr11);
2751
cg->stopUsingRegister(gr11);
2752
2753
generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel);
2754
TR::LabelSymbol *doneMainlineLabel = generateLabelSymbol(cg);
2755
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneMainlineLabel, mainlineDeps);
2756
}
2757
else
2758
generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel);
2759
2760
// OOL begin.
2761
//
2762
discontiguousArrayOOL->swapInstructionListsWithCompilation();
2763
{
2764
TR::Instruction *OOLLabelInstr = generateLabelInstruction(cg, TR::InstOpCode::label, node, discontiguousArrayLabel);
2765
// XXX: Temporary fix, OOL instruction stream does not pick up live locals or monitors correctly.
2766
TR_ASSERT(!OOLLabelInstr->getLiveLocals() && !OOLLabelInstr->getLiveMonitors(), "Expecting first OOL instruction to not have live locals/monitors info");
2767
OOLLabelInstr->setLiveLocals(OOLBranchInstr->getLiveLocals());
2768
OOLLabelInstr->setLiveMonitors(OOLBranchInstr->getLiveMonitors());
2769
2770
if (needsBoundCheckOOL)
2771
{
2772
TR_ASSERT(needsBoundCheck, "Inconsistent state, needs bound check OOL but doesn't need bound check");
2773
2774
TR::MemoryReference *discontiguousArraySizeMR = TR::MemoryReference::createWithDisplacement(cg, baseArrayReg, fej9->getOffsetOfDiscontiguousArraySizeField(), 4);
2775
TR::Register *arrayLengthScratchReg = srm->findOrCreateScratchRegister();
2776
2777
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, arrayLengthScratchReg, discontiguousArraySizeMR);
2778
2779
TR::Register *condReg = srm->findOrCreateScratchRegister(TR_CCR);
2780
2781
// Do the bound check using the discontiguous array length.
2782
genBoundCheck(cg, node, indexReg, indexChild->getInt(), arrayLengthScratchReg, arrayLengthChild->getInt(), condReg, noTrap);
2783
2784
srm->reclaimScratchRegister(condReg);
2785
srm->reclaimScratchRegister(arrayLengthScratchReg);
2786
}
2787
2788
TR_ASSERT(!(doLoadOrStore && doAddressComputation), "Unexpected condition");
2789
2790
TR::Register *arrayletReg;
2791
TR::DataType dt = loadOrStoreChild->getDataType();
2792
2793
if (doLoadOrStore || doAddressComputation)
2794
{
2795
arrayletReg = doAddressComputation ? loadOrStoreReg : /* Needs to be in !gr0 in this case */cg->allocateRegister();
2796
2797
// Generate the base+offset address pair into the arraylet.
2798
//
2799
int32_t elementSize = dt == TR::Address ? TR::Compiler->om.sizeofReferenceField() : TR::Symbol::convertTypeToSize(dt);
2800
TR::Register *arrayletOffsetReg;
2801
int32_t arrayletOffsetVal;
2802
2803
if (indexReg)
2804
arrayletOffsetReg = srm->findOrCreateScratchRegister();
2805
2806
genArrayletAccessAddr(cg, node, elementSize, baseArrayReg, indexReg, indexChild->getInt(), arrayletReg, arrayletOffsetReg, arrayletOffsetVal);
2807
2808
// Decompress the arraylet pointer if necessary.
2809
genDecompressPointer(cg, node, arrayletReg);
2810
2811
if (doLoadOrStore)
2812
{
2813
// Generate the load or store.
2814
//
2815
if (loadOrStoreChild->getOpCode().isStore())
2816
{
2817
bool isUnsigned = loadOrStoreChild->getOpCode().isUnsigned();
2818
TR::InstOpCode::Mnemonic storeOp = getLoadOrStoreFromDataType(cg, dt, elementSize, isUnsigned, false);
2819
2820
if (storeOp == TR::InstOpCode::std && comp->target().is32Bit())
2821
{
2822
// Store using consecutive stws.
2823
TR_ASSERT(elementSize == 8 && loadOrStoreChild->getSecondChild()->getRegister()->getRegisterPair(), "Expecting 64-bit store value to be in a register pair");
2824
if (indexReg)
2825
{
2826
TR::MemoryReference *arrayletMR = TR::MemoryReference::createWithIndexReg(cg, arrayletReg, arrayletOffsetReg, 4);
2827
generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, arrayletMR, loadOrStoreChild->getSecondChild()->getRegister()->getHighOrder());
2828
2829
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, arrayletOffsetReg, arrayletOffsetReg, 4);
2830
2831
TR::MemoryReference *arrayletMR2 = TR::MemoryReference::createWithIndexReg(cg, arrayletReg, arrayletOffsetReg, 4);
2832
generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, arrayletMR2, loadOrStoreChild->getSecondChild()->getRegister()->getLowOrder());
2833
}
2834
else
2835
{
2836
TR::MemoryReference *arrayletMR = TR::MemoryReference::createWithDisplacement(cg, arrayletReg, arrayletOffsetVal, 4);
2837
TR::MemoryReference *arrayletMR2 = TR::MemoryReference::createWithDisplacement(cg, arrayletReg, arrayletOffsetVal + 4, 4);
2838
generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, arrayletMR, loadOrStoreChild->getSecondChild()->getRegister()->getHighOrder());
2839
generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, arrayletMR2, loadOrStoreChild->getSecondChild()->getRegister()->getLowOrder());
2840
}
2841
}
2842
else
2843
{
2844
TR::MemoryReference *arrayletMR =
2845
indexReg ? TR::MemoryReference::createWithIndexReg(cg, arrayletReg, arrayletOffsetReg, elementSize) :
2846
TR::MemoryReference::createWithDisplacement(cg, arrayletReg, arrayletOffsetVal, elementSize);
2847
generateMemSrc1Instruction(cg, storeOp, node, arrayletMR, loadOrStoreChild->getSecondChild()->getRegister());
2848
}
2849
}
2850
else
2851
{
2852
TR_ASSERT(loadOrStoreChild->getOpCode().isConversion() || loadOrStoreChild->getOpCode().isLoad(), "Unexpected op");
2853
2854
bool isUnsigned = loadOrStoreChild->getOpCode().isUnsigned();
2855
TR::InstOpCode::Mnemonic loadOp = getLoadOrStoreFromDataType(cg, dt, elementSize, isUnsigned, true);
2856
2857
if (loadOp == TR::InstOpCode::ld && comp->target().is32Bit())
2858
{
2859
// Load using consecutive lwzs.
2860
TR_ASSERT(elementSize == 8 && loadOrStoreReg->getRegisterPair(), "Expecting 64-bit load value to be in a register pair");
2861
if (indexReg)
2862
{
2863
TR::MemoryReference *arrayletMR = TR::MemoryReference::createWithIndexReg(cg, arrayletReg, arrayletOffsetReg, 4);
2864
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, loadOrStoreReg->getHighOrder(), arrayletMR);
2865
2866
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, arrayletOffsetReg, arrayletOffsetReg, 4);
2867
2868
TR::MemoryReference *arrayletMR2 = TR::MemoryReference::createWithIndexReg(cg, arrayletReg, arrayletOffsetReg, 4);
2869
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, loadOrStoreReg->getLowOrder(), arrayletMR2);
2870
}
2871
else
2872
{
2873
TR::MemoryReference *arrayletMR = TR::MemoryReference::createWithDisplacement(cg, arrayletReg, arrayletOffsetVal, 4);
2874
TR::MemoryReference *arrayletMR2 = TR::MemoryReference::createWithDisplacement(cg, arrayletReg, arrayletOffsetVal + 4, 4);
2875
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, loadOrStoreReg->getHighOrder(), arrayletMR);
2876
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, loadOrStoreReg->getLowOrder(), arrayletMR2);
2877
}
2878
}
2879
else
2880
{
2881
TR::MemoryReference *arrayletMR =
2882
indexReg ? TR::MemoryReference::createWithIndexReg(cg, arrayletReg, arrayletOffsetReg, elementSize) :
2883
TR::MemoryReference::createWithDisplacement(cg, arrayletReg, arrayletOffsetVal, elementSize);
2884
generateTrg1MemInstruction(cg, loadOp, node, loadOrStoreReg, arrayletMR);
2885
}
2886
2887
if (doLoadDecompress)
2888
{
2889
TR_ASSERT(dt == TR::Address, "Expecting loads with decompression trees to have data type TR::Address");
2890
genDecompressPointer(cg, node, loadOrStoreReg);
2891
}
2892
}
2893
2894
cg->stopUsingRegister(arrayletReg);
2895
}
2896
else
2897
{
2898
if (indexReg)
2899
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, loadOrStoreReg, loadOrStoreReg, arrayletOffsetReg);
2900
else
2901
addConstantToInteger(node, loadOrStoreReg, loadOrStoreReg, arrayletOffsetVal, cg);
2902
}
2903
2904
if (indexReg)
2905
srm->reclaimScratchRegister(arrayletOffsetReg);
2906
}
2907
2908
const uint32_t numOOLDeps = 1 + (doLoadOrStore ? 1 : 0) + (needsBoundCheck && arrayLengthReg ? 1 : 0) + (loadOrStoreReg ? (loadOrStoreReg->getRegisterPair() ? 2 : 1) : 0)
2909
+ (indexReg ? 1 : 0) + srm->numAvailableRegisters();
2910
TR::RegisterDependencyConditions *OOLDeps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, numOOLDeps, cg->trMemory());
2911
OOLDeps->addPostCondition(baseArrayReg, TR::RealRegister::NoReg);
2912
TR_ASSERT(OOLDeps->getPostConditions()->getRegisterDependency(0)->getRegister() == baseArrayReg, "Unexpected register");
2913
OOLDeps->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0();
2914
if (doLoadOrStore)
2915
{
2916
OOLDeps->addPostCondition(arrayletReg, TR::RealRegister::NoReg);
2917
TR_ASSERT(OOLDeps->getPostConditions()->getRegisterDependency(1)->getRegister() == arrayletReg, "Unexpected register");
2918
OOLDeps->getPostConditions()->getRegisterDependency(1)->setExcludeGPR0();
2919
}
2920
if (indexReg)
2921
OOLDeps->addPostCondition(indexReg, TR::RealRegister::NoReg);
2922
if (loadOrStoreReg)
2923
{
2924
if (loadOrStoreReg->getRegisterPair())
2925
{
2926
TR_ASSERT(dt == TR::Int64 && comp->target().is32Bit(), "Unexpected register pair");
2927
OOLDeps->addPostCondition(loadOrStoreReg->getHighOrder(), TR::RealRegister::NoReg);
2928
OOLDeps->addPostCondition(loadOrStoreReg->getLowOrder(), TR::RealRegister::NoReg);
2929
}
2930
else
2931
OOLDeps->addPostCondition(loadOrStoreReg, TR::RealRegister::NoReg);
2932
}
2933
if (needsBoundCheck && arrayLengthReg)
2934
OOLDeps->addPostCondition(arrayLengthReg, TR::RealRegister::NoReg);
2935
srm->addScratchRegistersToDependencyList(OOLDeps);
2936
2937
srm->stopUsingRegisters();
2938
2939
TR::LabelSymbol *doneOOLLabel = generateLabelSymbol(cg);
2940
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneOOLLabel, OOLDeps);
2941
generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);
2942
}
2943
discontiguousArrayOOL->swapInstructionListsWithCompilation();
2944
//
2945
// OOL end.
2946
2947
cg->decReferenceCount(loadOrStoreChild);
2948
cg->decReferenceCount(baseArrayChild);
2949
cg->decReferenceCount(indexChild);
2950
2951
return NULL;
2952
}
2953
2954
static void VMoutlinedHelperArrayStoreCHKEvaluator(TR::Node *node, TR::Register *srcReg, TR::Register *dstReg, bool srcIsNonNull, TR::CodeGenerator *cg)
2955
{
2956
TR::Compilation * comp = cg->comp();
2957
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
2958
TR::CodeCache *codeCache = cg->getCodeCache();
2959
TR::LabelSymbol *doneArrayStoreCHKLabel = generateLabelSymbol(cg);
2960
TR::Register *rootClassReg = cg->allocateRegister();
2961
TR::Register *scratchReg = cg->allocateRegister();
2962
TR::Register *srcNullCondReg;
2963
2964
TR_PPCScratchRegisterDependencyConditions deps;
2965
2966
if (!srcIsNonNull)
2967
{
2968
srcNullCondReg = cg->allocateRegister(TR_CCR);
2969
generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, srcNullCondReg, srcReg, NULLVALUE);
2970
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneArrayStoreCHKLabel, srcNullCondReg);
2971
}
2972
2973
deps.addDependency(cg, dstReg, TR::RealRegister::gr3);
2974
deps.addDependency(cg, srcReg, TR::RealRegister::gr4);
2975
// Clobbered by the helper
2976
deps.addDependency(cg, NULL, TR::RealRegister::gr5);
2977
deps.addDependency(cg, NULL, TR::RealRegister::gr6);
2978
deps.addDependency(cg, scratchReg, TR::RealRegister::gr7);
2979
deps.addDependency(cg, rootClassReg, TR::RealRegister::gr11);
2980
2981
TR_OpaqueClassBlock *rootClass = fej9->getSystemClassFromClassName("java/lang/Object", 16);
2982
if (cg->wantToPatchClassPointer(rootClass, node))
2983
loadAddressConstantInSnippet(cg, node, (intptr_t) rootClass, rootClassReg, scratchReg,TR::InstOpCode::Op_load, false, NULL);
2984
else
2985
loadAddressConstant(cg, comp->compileRelocatableCode(), node, (intptr_t) rootClass, rootClassReg);
2986
2987
TR_CCPreLoadedCode helper = TR_arrayStoreCHK;
2988
uintptr_t helperAddr = (uintptr_t) codeCache->getCCPreLoadedCodeAddress(helper, cg);
2989
TR::SymbolReference *symRef = comp->getSymRefTab()->findOrCreatePerCodeCacheHelperSymbolRef(helper, helperAddr);
2990
2991
TR::Instruction *gcPoint = generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, helperAddr, new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 0, cg->trMemory()),
2992
symRef);
2993
gcPoint->PPCNeedsGCMap(0xFFFFFFFF);
2994
2995
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneArrayStoreCHKLabel, TR_PPCScratchRegisterDependencyConditions::createDependencyConditions(cg, NULL, &deps));
2996
2997
cg->stopUsingRegister(rootClassReg);
2998
cg->stopUsingRegister(scratchReg);
2999
3000
if (!srcIsNonNull)
3001
cg->stopUsingRegister(srcNullCondReg);
3002
}
3003
3004
TR::Register *outlinedHelperArrayStoreCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)
3005
{
3006
TR::Node *srcNode = node->getFirstChild()->getSecondChild();
3007
TR::Node *dstNode = node->getFirstChild()->getThirdChild();
3008
TR::Register *srcReg = cg->evaluate(srcNode);
3009
TR::Register *dstReg = cg->evaluate(dstNode);
3010
TR::Compilation* comp = cg->comp();
3011
3012
if (!srcNode->isNull())
3013
{
3014
VMoutlinedHelperArrayStoreCHKEvaluator(node, srcReg, dstReg, srcNode->isNonNull(), cg);
3015
}
3016
3017
cg->evaluate(node->getFirstChild());
3018
cg->decReferenceCount(node->getFirstChild());
3019
3020
return NULL;
3021
}
3022
3023
TR::Instruction *J9::Power::TreeEvaluator::generateVFTMaskInstruction(TR::CodeGenerator *cg, TR::Node *node, TR::Register *dstReg, TR::Register *srcReg, TR::Instruction *preced)
3024
{
3025
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
3026
uintptr_t mask = TR::Compiler->om.maskOfObjectVftField();
3027
bool isCompressed = TR::Compiler->om.compressObjectReferences();
3028
if (~mask == 0)
3029
{
3030
// no mask instruction required
3031
return preced;
3032
}
3033
else
3034
{
3035
TR::InstOpCode::Mnemonic op = (cg->comp()->target().is64Bit() && !isCompressed) ? TR::InstOpCode::rldicr : TR::InstOpCode::rlwinm;
3036
return generateTrg1Src1Imm2Instruction(cg, op, node, dstReg, srcReg, 0, mask, preced);
3037
}
3038
}
3039
3040
TR::Instruction *J9::Power::TreeEvaluator::generateVFTMaskInstruction(TR::CodeGenerator *cg, TR::Node *node, TR::Register *reg, TR::Instruction *preced)
3041
{
3042
return TR::TreeEvaluator::generateVFTMaskInstruction(cg, node, reg, reg, preced);
3043
}
3044
3045
static TR::Instruction *genTestIsSuper(TR::Node *node, TR::Register *objClassReg, TR::Register *castClassReg, TR::Register *crReg, TR::Register *scratch1Reg,
3046
TR::Register *scratch2Reg, int32_t castClassDepth, TR::LabelSymbol *failLabel, TR::Instruction *cursor, TR::CodeGenerator *cg, bool depthInReg2 = false)
3047
{
3048
TR::Compilation *comp = cg->comp();
3049
int32_t superClassOffset = castClassDepth * TR::Compiler->om.sizeofReferenceAddress();
3050
bool outOfBound = (!depthInReg2 && (superClassOffset > UPPER_IMMED || superClassOffset < LOWER_IMMED)) ? true : false;
3051
#ifdef OMR_GC_COMPRESSED_POINTERS
3052
// objClassReg contains the class offset so we may need to generate code
3053
// to convert from class offset to real J9Class pointer
3054
#endif
3055
cursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, scratch1Reg,
3056
TR::MemoryReference::createWithDisplacement(cg, objClassReg, offsetof(J9Class, classDepthAndFlags), TR::Compiler->om.sizeofReferenceAddress()), cursor);
3057
if (outOfBound)
3058
{
3059
cursor = loadConstant(cg, node, castClassDepth, scratch2Reg, cursor);
3060
}
3061
cursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, scratch1Reg, scratch1Reg, 0, J9AccClassDepthMask, cursor);
3062
3063
if (outOfBound || depthInReg2)
3064
{
3065
cursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, crReg, scratch1Reg, scratch2Reg, cursor);
3066
}
3067
else
3068
{
3069
cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, crReg, scratch1Reg, castClassDepth, cursor);
3070
}
3071
cursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::ble, node, failLabel, crReg, cursor);
3072
3073
if (outOfBound || depthInReg2)
3074
{
3075
if (comp->target().is64Bit())
3076
cursor = generateShiftLeftImmediateLong(cg, node, scratch2Reg, scratch2Reg, 3, cursor);
3077
else
3078
cursor = generateShiftLeftImmediate(cg, node, scratch2Reg, scratch2Reg, 2, cursor);
3079
}
3080
#ifdef OMR_GC_COMPRESSED_POINTERS
3081
// objClassReg contains the class offset so we may need to generate code
3082
// to convert from class offset to real J9Class pointer
3083
#endif
3084
cursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, scratch1Reg,
3085
TR::MemoryReference::createWithDisplacement(cg, objClassReg, offsetof(J9Class, superclasses), TR::Compiler->om.sizeofReferenceAddress()), cursor);
3086
3087
if (outOfBound || depthInReg2)
3088
{
3089
cursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_loadx, node, scratch1Reg, TR::MemoryReference::createWithIndexReg(cg, scratch1Reg, scratch2Reg, TR::Compiler->om.sizeofReferenceAddress()),
3090
cursor);
3091
}
3092
else
3093
{
3094
cursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, scratch1Reg,
3095
TR::MemoryReference::createWithDisplacement(cg, scratch1Reg, superClassOffset, TR::Compiler->om.sizeofReferenceAddress()), cursor);
3096
}
3097
#ifdef OMR_GC_COMPRESSED_POINTERS
3098
// castClassReg has a class offset and scratch1Reg contains a J9Class pointer
3099
// May need to convert the J9Class pointer to a class offset
3100
#endif
3101
cursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmp, node, crReg, scratch1Reg, castClassReg, cursor);
3102
return (cursor);
3103
}
3104
3105
static void VMarrayStoreCHKEvaluator(TR::Node *node, TR::Register *src, TR::Register *dst, TR::Register *t1Reg, TR::Register *t2Reg, TR::Register *t3Reg, TR::Register *t4Reg,
3106
TR::Register *cndReg, TR::LabelSymbol *toWB, TR::LabelSymbol *fLabel, TR::CodeGenerator *cg)
3107
{
3108
TR::Compilation *comp = cg->comp();
3109
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
3110
3111
generateLoadJ9Class(node, t1Reg, dst, cg);
3112
generateLoadJ9Class(node, t2Reg, src, cg);
3113
3114
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, t1Reg,
3115
TR::MemoryReference::createWithDisplacement(cg, t1Reg, (int32_t)offsetof(J9ArrayClass, componentType), TR::Compiler->om.sizeofReferenceAddress()));
3116
3117
if (!comp->compileRelocatableCode() || comp->getOption(TR_UseSymbolValidationManager))
3118
{
3119
TR_OpaqueClassBlock *rootClass = fej9->getSystemClassFromClassName("java/lang/Object", 16);
3120
3121
if (cg->wantToPatchClassPointer(rootClass, node))
3122
{
3123
loadAddressConstantInSnippet(cg, node, (intptr_t) rootClass, t3Reg, t4Reg, TR::InstOpCode::Op_load, false, NULL);
3124
}
3125
else if (comp->compileRelocatableCode())
3126
{
3127
TR::StaticSymbol *sym = TR::StaticSymbol::create(comp->trHeapMemory(), TR::Address);
3128
sym->setStaticAddress(rootClass);
3129
sym->setClassObject();
3130
3131
loadAddressConstant(cg, true, node, (intptr_t) new (comp->trHeapMemory()) TR::SymbolReference(comp->getSymRefTab(), sym), t3Reg, NULL, false, TR_ClassAddress);
3132
}
3133
else
3134
{
3135
loadAddressConstant(cg, false, node, (intptr_t) rootClass, t3Reg);
3136
}
3137
3138
generateTrg1Src2Instruction(cg, TR::InstOpCode::Op_cmpl, node, cndReg, t1Reg, t3Reg);
3139
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, toWB, cndReg);
3140
}
3141
3142
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, t4Reg,
3143
TR::MemoryReference::createWithDisplacement(cg, t2Reg, (int32_t) offsetof(J9Class, castClassCache), TR::Compiler->om.sizeofReferenceAddress()));
3144
3145
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, t1Reg, t2Reg);
3146
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, toWB, cndReg);
3147
3148
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, t1Reg, t4Reg);
3149
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, toWB, cndReg);
3150
3151
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, t1Reg, t3Reg);
3152
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, toWB, cndReg);
3153
3154
if ((!comp->getOption(TR_DisableArrayStoreCheckOpts)) && node->getArrayComponentClassInNode())
3155
{
3156
TR_OpaqueClassBlock *castClass = (TR_OpaqueClassBlock *) node->getArrayComponentClassInNode();
3157
3158
if (cg->wantToPatchClassPointer(castClass, node))
3159
loadAddressConstantInSnippet(cg, node, (intptr_t) castClass, t3Reg, t4Reg,TR::InstOpCode::Op_load, false, NULL);
3160
else
3161
loadAddressConstant(cg, comp->compileRelocatableCode(), node, (intptr_t) castClass, t3Reg);
3162
3163
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, t1Reg, t3Reg);
3164
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, toWB, cndReg);
3165
}
3166
3167
#ifdef OMR_GC_COMPRESSED_POINTERS
3168
// For the following two instructions
3169
// we may need to convert the class offset from t1Reg into J9Class
3170
#endif
3171
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, t3Reg, TR::MemoryReference::createWithDisplacement(cg, t1Reg, (int32_t) offsetof(J9Class, romClass), TR::Compiler->om.sizeofReferenceAddress()));
3172
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, t4Reg,
3173
TR::MemoryReference::createWithDisplacement(cg, t1Reg, (int32_t) offsetof(J9Class, classDepthAndFlags), TR::Compiler->om.sizeofReferenceAddress()));
3174
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, t3Reg, TR::MemoryReference::createWithDisplacement(cg, t3Reg, (int32_t) offsetof(J9ROMClass, modifiers), 4));
3175
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, t4Reg, t4Reg, 0, J9AccClassDepthMask);
3176
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, t3Reg, t3Reg, 31, 0xFFFFFFFF);
3177
TR_ASSERT(J9AccClassArray == (1 << 16) && J9AccInterface == (1 << 9), "Verify code sequence is still right ...");
3178
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, t3Reg, t3Reg, cndReg, (J9AccClassArray | J9AccInterface) >> 1);
3179
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, fLabel, cndReg);
3180
genTestIsSuper(node, t2Reg, t1Reg, cndReg, t3Reg, t4Reg, 0, fLabel, cg->getAppendInstruction(), cg, true);
3181
3182
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, fLabel, cndReg);
3183
}
3184
3185
TR::Register *J9::Power::TreeEvaluator::ArrayStoreCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)
3186
{
3187
TR::Compilation *comp = cg->comp();
3188
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
3189
static bool oldArrayStoreCHK = feGetEnv("TR_newArrayStoreCheck") == NULL;
3190
if (!comp->compileRelocatableCode() && !comp->getOptions()->realTimeGC() && !comp->useCompressedPointers() && !oldArrayStoreCHK)
3191
return outlinedHelperArrayStoreCHKEvaluator(node, cg);
3192
3193
// Note: we take advantage of the register conventions of the helpers by limiting register usages on
3194
// the fast-path (most likely 4 registers; at most, 6 registers)
3195
3196
TR::Node * firstChild = node->getFirstChild();
3197
3198
TR::Node *sourceChild = firstChild->getSecondChild();
3199
TR::Node *destinationChild = firstChild->getChild(2);
3200
3201
if (comp->useCompressedPointers() && firstChild->getOpCode().isIndirect())
3202
{
3203
while ((sourceChild->getNumChildren() > 0) && (sourceChild->getOpCodeValue() != TR::a2l))
3204
sourceChild = sourceChild->getFirstChild();
3205
if (sourceChild->getOpCodeValue() == TR::a2l)
3206
sourceChild = sourceChild->getFirstChild();
3207
}
3208
3209
// Since ArrayStoreCHK doesn't have the shape of the corresponding helper call we have to create this tree
3210
// so we can have it evaluated out of line
3211
TR::Node *helperCallNode = TR::Node::createWithSymRef(node, TR::call, 2, node->getSymbolReference());
3212
helperCallNode->setAndIncChild(0, sourceChild);
3213
helperCallNode->setAndIncChild(1, destinationChild);
3214
if (comp->getOption(TR_TraceCG))
3215
{
3216
traceMsg(comp, "%s: Creating and evaluating the following tree to generate the necessary helper call for this node\n", node->getOpCode().getName());
3217
cg->getDebug()->print(comp->getOutFile(), helperCallNode);
3218
}
3219
3220
TR::Register *srcReg, *dstReg;
3221
TR::Register *condReg, *temp1Reg, *temp2Reg, *temp3Reg, *temp4Reg;
3222
TR::LabelSymbol *wbLabel, *startLabel;
3223
TR::RegisterDependencyConditions *conditions;
3224
3225
wbLabel = generateLabelSymbol(cg);
3226
3227
dstReg = cg->evaluate(destinationChild);
3228
srcReg = cg->evaluate(sourceChild);
3229
3230
conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(9, 9, cg->trMemory());
3231
temp1Reg = cg->allocateRegister();
3232
temp2Reg = cg->allocateRegister();
3233
temp3Reg = cg->allocateRegister();
3234
temp4Reg = cg->allocateRegister();
3235
condReg = cg->allocateRegister(TR_CCR);
3236
3237
TR::addDependency(conditions, dstReg, TR::RealRegister::NoReg, TR_GPR, cg);
3238
conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();
3239
conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();
3240
TR::addDependency(conditions, srcReg, TR::RealRegister::NoReg, TR_GPR, cg);
3241
conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();
3242
conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();
3243
TR::addDependency(conditions, temp1Reg, TR::RealRegister::NoReg, TR_GPR, cg);
3244
conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();
3245
conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();
3246
TR::addDependency(conditions, temp2Reg, TR::RealRegister::NoReg, TR_GPR, cg);
3247
conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();
3248
conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();
3249
TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);
3250
conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();
3251
conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();
3252
TR::addDependency(conditions, temp4Reg, TR::RealRegister::NoReg, TR_GPR, cg);
3253
conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();
3254
conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();
3255
TR::addDependency(conditions, condReg, TR::RealRegister::cr0, TR_CCR, cg);
3256
3257
//--Generate Test to see if 'sourceRegister' is NULL
3258
generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, condReg, srcReg, NULLVALUE);
3259
//--Generate Jump past ArrayStoreCHKEvaluator
3260
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, wbLabel, condReg);
3261
3262
TR::LabelSymbol *helperCall = generateLabelSymbol(cg);
3263
VMarrayStoreCHKEvaluator(node, srcReg, dstReg, temp1Reg, temp2Reg, temp3Reg, temp4Reg, condReg, wbLabel, helperCall, cg);
3264
3265
TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(helperCallNode, TR::call, NULL, helperCall, wbLabel, cg);
3266
cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);
3267
cg->decReferenceCount(helperCallNode->getFirstChild());
3268
cg->decReferenceCount(helperCallNode->getSecondChild());
3269
3270
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, wbLabel, conditions);
3271
cg->evaluate(firstChild);
3272
3273
cg->decReferenceCount(firstChild);
3274
3275
cg->stopUsingRegister(temp1Reg);
3276
cg->stopUsingRegister(temp2Reg);
3277
cg->stopUsingRegister(temp3Reg);
3278
cg->stopUsingRegister(temp4Reg);
3279
cg->stopUsingRegister(condReg);
3280
3281
return NULL;
3282
}
3283
3284
TR::Register *J9::Power::TreeEvaluator::ArrayCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)
3285
{
3286
return TR::TreeEvaluator::VMarrayCheckEvaluator(node, cg);
3287
}
3288
3289
TR::Register *J9::Power::TreeEvaluator::conditionalHelperEvaluator(TR::Node *node, TR::CodeGenerator *cg)
3290
{
3291
// There are two points which have to be considered for this evaluator:
3292
// 1) This conditional tree is of a special form which is lowered just
3293
// before instruction selection. This means the conditional is invisible
3294
// to the control flow analysis. As such, we have to treat it just as
3295
// part of a basic block;
3296
// 2) The two opCodes using this evaluator are intended as quick JVMPI
3297
// probes. They should not impact the normal code (in terms of performance).
3298
// As such, their call evaluation will be specially treated not to go
3299
// through the normal linkage. OTI will preserve all the registers as
3300
// needed.
3301
3302
TR::RegisterDependencyConditions *conditions;
3303
TR::Register *cndReg, *jumpReg, *valReg;
3304
TR::Node *testNode = node->getFirstChild(), *callNode = node->getSecondChild();
3305
TR::Node *firstChild = testNode->getFirstChild(), *secondChild = testNode->getSecondChild();
3306
int32_t value, i, numArgs = callNode->getNumChildren();
3307
3308
conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(4, 4, cg->trMemory());
3309
3310
TR_ASSERT(numArgs <= 2, "Unexpected number of arguments for helper.");
3311
3312
// Helper arguments are in reversed order of the private linkage
3313
// Argument registers are not needed to be split since the helper will
3314
// preserve all of them.
3315
int32_t iArgIndex = 0, fArgIndex = 0;
3316
TR::Linkage *linkage = cg->createLinkage(TR_Private);
3317
for (i = numArgs - 1; i >= 0; i--)
3318
{
3319
TR::Register *argReg = cg->evaluate(callNode->getChild(i));
3320
TR::addDependency(conditions, argReg, (argReg->getKind() == TR_GPR) ? // Didn't consider Long here
3321
linkage->getProperties().getIntegerArgumentRegister(iArgIndex++) : linkage->getProperties().getFloatArgumentRegister(fArgIndex++), argReg->getKind(), cg);
3322
}
3323
3324
cndReg = cg->allocateRegister(TR_CCR);
3325
jumpReg = cg->evaluate(firstChild);
3326
TR::addDependency(conditions, cndReg, TR::RealRegister::NoReg, TR_CCR, cg);
3327
TR::addDependency(conditions, jumpReg, TR::RealRegister::gr11, TR_GPR, cg);
3328
3329
if (secondChild->getOpCode().isLoadConst() && (value = secondChild->getInt()) <= UPPER_IMMED && value >= LOWER_IMMED)
3330
{
3331
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, testNode, cndReg, jumpReg, value);
3332
}
3333
else
3334
{
3335
valReg = cg->evaluate(secondChild);
3336
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, testNode, cndReg, jumpReg, valReg);
3337
}
3338
3339
TR::Instruction *gcPoint;
3340
TR::LabelSymbol *snippetLabel = cg->lookUpSnippet(TR::Snippet::IsHelperCall, node->getSymbolReference());
3341
if (snippetLabel == NULL)
3342
{
3343
snippetLabel = generateLabelSymbol(cg);
3344
cg->addSnippet(new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference()));
3345
}
3346
gcPoint = generateDepConditionalBranchInstruction(cg, testNode->getOpCodeValue() == TR::icmpeq ? TR::InstOpCode::beql : TR::InstOpCode::bnel, node, snippetLabel, cndReg, conditions);
3347
gcPoint->PPCNeedsGCMap(0xFFFFFFFF);
3348
3349
cg->stopUsingRegister(cndReg);
3350
for (i = numArgs - 1; i >= 0; i--)
3351
cg->decReferenceCount(callNode->getChild(i));
3352
cg->decReferenceCount(firstChild);
3353
cg->decReferenceCount(secondChild);
3354
cg->decReferenceCount(testNode);
3355
cg->decReferenceCount(callNode);
3356
return NULL;
3357
}
3358
3359
TR::Register *J9::Power::TreeEvaluator::flushEvaluator(TR::Node *node, TR::CodeGenerator *cg)
3360
{
3361
TR::ILOpCodes opCode = node->getOpCodeValue();
3362
3363
if (opCode == TR::allocationFence)
3364
{
3365
if (!node->canOmitSync())
3366
generateInstruction(cg, TR::InstOpCode::lwsync, node);
3367
}
3368
else
3369
{
3370
if (opCode == TR::loadFence)
3371
{
3372
if (cg->comp()->target().cpu.is(OMR_PROCESSOR_PPC_P7))
3373
generateInstruction(cg, TR::InstOpCode::lwsync, node);
3374
else
3375
generateInstruction(cg, TR::InstOpCode::isync, node);
3376
}
3377
else if (opCode == TR::storeFence)
3378
generateInstruction(cg, TR::InstOpCode::lwsync, node);
3379
else if (opCode == TR::fullFence)
3380
{
3381
if (node->canOmitSync())
3382
generateLabelInstruction(cg, TR::InstOpCode::label, node, generateLabelSymbol(cg));
3383
else
3384
generateInstruction(cg, TR::InstOpCode::sync, node);
3385
}
3386
}
3387
3388
return NULL;
3389
}
3390
3391
static
3392
void genCheckCastTransitionToNextSequence(TR::Node *node, J9::TreeEvaluator::InstanceOfOrCheckCastSequences *iter, TR::LabelSymbol *nextSequenceLabel, TR::LabelSymbol *trueLabel, TR::Register *condReg, TR::CodeGenerator *cg)
3393
{
3394
J9::TreeEvaluator::InstanceOfOrCheckCastSequences current = *iter++;
3395
3396
if (current == J9::TreeEvaluator::EvaluateCastClass || current == J9::TreeEvaluator::LoadObjectClass)
3397
return;
3398
if (current == J9::TreeEvaluator::NullTest && node->getOpCodeValue() == TR::checkcastAndNULLCHK)
3399
return;
3400
3401
J9::TreeEvaluator::InstanceOfOrCheckCastSequences next = *iter;
3402
3403
while (next == J9::TreeEvaluator::EvaluateCastClass || next == J9::TreeEvaluator::LoadObjectClass)
3404
next = *++iter;
3405
3406
bool nextSequenceIsOutOfLine = next == J9::TreeEvaluator::HelperCall || next == J9::TreeEvaluator::GoToFalse;
3407
3408
if (nextSequenceIsOutOfLine)
3409
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, nextSequenceLabel, condReg);
3410
else
3411
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, trueLabel, condReg);
3412
}
3413
3414
static
3415
void genInstanceOfTransitionToNextSequence(TR::Node *node, J9::TreeEvaluator::InstanceOfOrCheckCastSequences *iter, TR::LabelSymbol *nextSequenceLabel, TR::LabelSymbol *doneLabel, TR::Register *condReg, TR::Register *resultReg, bool resultRegInitialValue, TR::LabelSymbol *oppositeResultLabel, bool profiledClassIsInstanceOf, TR::CodeGenerator *cg)
3416
{
3417
J9::TreeEvaluator::InstanceOfOrCheckCastSequences current = *iter++;
3418
3419
if (current == J9::TreeEvaluator::EvaluateCastClass || current == J9::TreeEvaluator::LoadObjectClass)
3420
return;
3421
if (current == J9::TreeEvaluator::NullTest && node->getOpCodeValue() == TR::checkcastAndNULLCHK)
3422
return;
3423
if (current == J9::TreeEvaluator::GoToFalse)
3424
return;
3425
3426
J9::TreeEvaluator::InstanceOfOrCheckCastSequences next = *iter;
3427
3428
while (next == J9::TreeEvaluator::EvaluateCastClass || next == J9::TreeEvaluator::LoadObjectClass)
3429
next = *++iter;
3430
3431
if (next == J9::TreeEvaluator::GoToFalse && resultRegInitialValue == false)
3432
nextSequenceLabel = doneLabel;
3433
3434
bool nextSequenceIsOutOfLine = next == J9::TreeEvaluator::HelperCall;
3435
3436
if (current == J9::TreeEvaluator::NullTest)
3437
{
3438
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, resultRegInitialValue == false ? doneLabel : oppositeResultLabel, condReg);
3439
}
3440
else if (current == J9::TreeEvaluator::CastClassCacheTest)
3441
{
3442
if (resultRegInitialValue == true)
3443
{
3444
if (nextSequenceIsOutOfLine)
3445
{
3446
generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, doneLabel, condReg);
3447
generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, nextSequenceLabel, condReg);
3448
// Fall through to oppositeResultLabel
3449
}
3450
else
3451
{
3452
generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, doneLabel, condReg);
3453
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, oppositeResultLabel, condReg);
3454
// Fall through to nextSequenceLabel
3455
}
3456
}
3457
else
3458
{
3459
if (nextSequenceIsOutOfLine)
3460
{
3461
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg);
3462
generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, nextSequenceLabel, condReg);
3463
// Fall through to oppositeResultLabel
3464
}
3465
else
3466
{
3467
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg);
3468
generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, oppositeResultLabel, condReg);
3469
// Fall through to nextSequenceLabel
3470
}
3471
}
3472
}
3473
else if (current == J9::TreeEvaluator::ProfiledClassTest)
3474
{
3475
if (resultRegInitialValue == true)
3476
{
3477
if (profiledClassIsInstanceOf)
3478
{
3479
if (nextSequenceIsOutOfLine)
3480
{
3481
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg);
3482
generateLabelInstruction(cg, TR::InstOpCode::b, node, nextSequenceLabel);
3483
}
3484
else
3485
{
3486
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg);
3487
}
3488
}
3489
else
3490
{
3491
if (nextSequenceIsOutOfLine)
3492
{
3493
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, nextSequenceLabel, condReg);
3494
// Fall through to oppositeResultLabel
3495
}
3496
else
3497
{
3498
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, oppositeResultLabel, condReg);
3499
}
3500
}
3501
}
3502
else
3503
{
3504
if (profiledClassIsInstanceOf)
3505
{
3506
if (nextSequenceIsOutOfLine)
3507
{
3508
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, nextSequenceLabel, condReg);
3509
// Fall through to oppositeResultLabel
3510
}
3511
else
3512
{
3513
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, oppositeResultLabel, condReg);
3514
}
3515
}
3516
else
3517
{
3518
if (nextSequenceIsOutOfLine)
3519
{
3520
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg);
3521
generateLabelInstruction(cg, TR::InstOpCode::b, node, nextSequenceLabel);
3522
}
3523
else
3524
{
3525
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg);
3526
}
3527
}
3528
}
3529
}
3530
else
3531
{
3532
if (nextSequenceIsOutOfLine)
3533
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, nextSequenceLabel, condReg);
3534
else
3535
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, resultRegInitialValue == true ? doneLabel : oppositeResultLabel, condReg);
3536
}
3537
}
3538
3539
static
3540
void genInstanceOfOrCheckCastClassEqualityTest(TR::Node *node, TR::Register *condReg, TR::Register *instanceClassReg, TR::Register *castClassReg, TR::CodeGenerator *cg)
3541
{
3542
generateTrg1Src2Instruction(cg, TR::InstOpCode::Op_cmpl, node, condReg, instanceClassReg, castClassReg);
3543
3544
// At this point condReg[eq] will be set if the cast class matches the instance class. Caller is responsible for acting on the result.
3545
}
3546
3547
static
3548
void genInstanceOfOrCheckCastSuperClassTest(TR::Node *node, TR::Register *condReg, TR::Register *instanceClassReg, TR::Register *castClassReg, int32_t castClassDepth, TR::LabelSymbol *falseLabel, TR_PPCScratchRegisterManager *srm, TR::CodeGenerator *cg)
3549
{
3550
TR::Compilation *comp = cg->comp();
3551
3552
// Compare the instance class depth to the cast class depth. If the instance class depth is less than or equal to
3553
// to the cast class depth then the cast class cannot be a superclass of the instance class.
3554
//
3555
TR::Register *instanceClassDepthReg = srm->findOrCreateScratchRegister();
3556
TR::Register *castClassDepthReg = NULL;
3557
generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, instanceClassDepthReg,
3558
TR::MemoryReference::createWithDisplacement(cg, instanceClassReg, offsetof(J9Class, classDepthAndFlags), TR::Compiler->om.sizeofReferenceAddress()));
3559
static_assert(J9AccClassDepthMask < UINT_MAX, "Class depth is not containable in 32 bits");
3560
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, instanceClassDepthReg, instanceClassDepthReg, 0, J9AccClassDepthMask);
3561
if (castClassDepth <= UPPER_IMMED && castClassDepth >= LOWER_IMMED)
3562
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, condReg, instanceClassDepthReg, castClassDepth);
3563
else
3564
{
3565
castClassDepthReg = srm->findOrCreateScratchRegister();
3566
loadConstant(cg, node, castClassDepth, castClassDepthReg);
3567
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, condReg, instanceClassDepthReg, castClassDepthReg);
3568
}
3569
srm->reclaimScratchRegister(instanceClassDepthReg);
3570
3571
// At this point condReg[gt] will be set if the instance class depth is greater than the cast class depth.
3572
//
3573
generateConditionalBranchInstruction(cg, TR::InstOpCode::ble, node, falseLabel, condReg);
3574
3575
// Load the superclasses array of the instance class and check if the superclass that appears at the depth of the cast class is in fact the cast class.
3576
// If not, the instance class and cast class are not in the same hierarchy.
3577
//
3578
TR::Register *instanceClassSuperClassesArrayReg = srm->findOrCreateScratchRegister();
3579
TR::Register *instanceClassSuperClassReg = srm->findOrCreateScratchRegister();
3580
3581
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, instanceClassSuperClassesArrayReg,
3582
TR::MemoryReference::createWithDisplacement(cg, instanceClassReg, offsetof(J9Class, superclasses), TR::Compiler->om.sizeofReferenceAddress()));
3583
3584
int32_t castClassDepthOffset = castClassDepth * TR::Compiler->om.sizeofReferenceAddress();
3585
if (castClassDepthOffset <= UPPER_IMMED && castClassDepthOffset >= LOWER_IMMED)
3586
{
3587
generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, instanceClassSuperClassReg,
3588
TR::MemoryReference::createWithDisplacement(cg, instanceClassSuperClassesArrayReg, castClassDepthOffset, TR::Compiler->om.sizeofReferenceAddress()));
3589
}
3590
else
3591
{
3592
if (!castClassDepthReg)
3593
{
3594
castClassDepthReg = srm->findOrCreateScratchRegister();
3595
if (0x00008000 == HI_VALUE(castClassDepthOffset))
3596
{
3597
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addis, node, castClassDepthReg, instanceClassSuperClassesArrayReg, 0x7FFF);
3598
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addis, node, castClassDepthReg, castClassDepthReg, 0x1);
3599
}
3600
else
3601
{
3602
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addis, node, castClassDepthReg, instanceClassSuperClassesArrayReg, HI_VALUE(castClassDepthOffset));
3603
}
3604
generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, instanceClassSuperClassReg,
3605
TR::MemoryReference::createWithDisplacement(cg, castClassDepthReg, LO_VALUE(castClassDepthOffset), TR::Compiler->om.sizeofReferenceAddress()));
3606
}
3607
else
3608
{
3609
if (comp->target().is64Bit())
3610
generateShiftLeftImmediateLong(cg, node, castClassDepthReg, castClassDepthReg, 3);
3611
else
3612
generateShiftLeftImmediate(cg, node, castClassDepthReg, castClassDepthReg, 2);
3613
generateTrg1MemInstruction(cg, TR::InstOpCode::Op_loadx, node, instanceClassSuperClassReg, TR::MemoryReference::createWithIndexReg(cg, instanceClassSuperClassesArrayReg, castClassDepthReg, TR::Compiler->om.sizeofReferenceAddress()));
3614
}
3615
}
3616
generateTrg1Src2Instruction(cg, TR::InstOpCode::Op_cmpl, node, condReg, instanceClassSuperClassReg, castClassReg);
3617
if (castClassDepthReg)
3618
srm->reclaimScratchRegister(castClassDepthReg);
3619
srm->reclaimScratchRegister(instanceClassSuperClassesArrayReg);
3620
srm->reclaimScratchRegister(instanceClassSuperClassReg);
3621
3622
// At this point condReg[eq] will be set if the cast class is a superclass of the instance class. Caller is responsible for acting on the result.
3623
}
3624
3625
static
3626
void genInstanceOfOrCheckCastArbitraryClassTest(TR::Node *node, TR::Register *condReg, TR::Register *instanceClassReg, TR_OpaqueClassBlock *arbitraryClass, TR_PPCScratchRegisterManager *srm, TR::CodeGenerator *cg)
3627
{
3628
TR::Compilation *comp = cg->comp();
3629
TR::Register *arbitraryClassReg = srm->findOrCreateScratchRegister();
3630
if (comp->compileRelocatableCode() && comp->getOption(TR_UseSymbolValidationManager))
3631
{
3632
TR::StaticSymbol *sym = TR::StaticSymbol::create(comp->trHeapMemory(), TR::Address);
3633
sym->setStaticAddress(arbitraryClass);
3634
sym->setClassObject();
3635
3636
loadAddressConstant(cg, true, node, (intptr_t) new (comp->trHeapMemory()) TR::SymbolReference(comp->getSymRefTab(), sym), arbitraryClassReg, NULL, false, TR_ClassAddress);
3637
}
3638
else
3639
{
3640
loadAddressConstant(cg, comp->compileRelocatableCode(), node, (intptr_t)arbitraryClass, arbitraryClassReg);
3641
}
3642
genInstanceOfOrCheckCastClassEqualityTest(node, condReg, instanceClassReg, arbitraryClassReg, cg);
3643
srm->reclaimScratchRegister(arbitraryClassReg);
3644
3645
// At this point condReg[eq] will be set if the cast class matches the arbitrary class. Caller is responsible for acting on the result.
3646
}
3647
3648
static
3649
void genInstanceOfCastClassCacheTest(TR::Node *node, TR::Register *condReg, TR::Register *instanceClassReg, TR::Register *castClassReg, TR_PPCScratchRegisterManager *srm, TR::CodeGenerator *cg)
3650
{
3651
TR::Compilation *comp = cg->comp();
3652
3653
// Compare the cast class against the cache on the instance class.
3654
// If they are the same the cast is successful.
3655
// If not it's either because the cache class does not match the cast class, or it does match except the cache class has the low bit set, which means the cast is not successful.
3656
//
3657
TR::Register *castClassCacheReg = srm->findOrCreateScratchRegister();
3658
generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, castClassCacheReg,
3659
TR::MemoryReference::createWithDisplacement(cg, instanceClassReg, offsetof(J9Class, castClassCache), TR::Compiler->om.sizeofReferenceAddress()));
3660
generateTrg1Src2Instruction(cg, TR::InstOpCode::XOR, node, castClassCacheReg, castClassCacheReg, castClassReg);
3661
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::Op_cmpli, node, condReg, castClassCacheReg, 1);
3662
3663
// At this point condReg[lt] will be set if the cast is successful, condReg[eq] will be set if the cast is unsuccessful, and condReg[gt] will be set if the cache class did not match the cast class.
3664
// Caller is responsible for acting on the result.
3665
}
3666
3667
static
3668
void genCheckCastCastClassCacheTest(TR::Node *node, TR::Register *condReg, TR::Register *instanceClassReg, TR::Register *castClassReg, TR_PPCScratchRegisterManager *srm, TR::CodeGenerator *cg)
3669
{
3670
TR::Compilation *comp = cg->comp();
3671
3672
// Compare the cast class against the cache on the instance class.
3673
// If they are the same the cast is successful.
3674
// If not it's either because the cache class does not match the cast class, or it does match except the cache class has the low bit set, which means the cast is invalid.
3675
//
3676
TR::Register *castClassCacheReg = srm->findOrCreateScratchRegister();
3677
generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, castClassCacheReg,
3678
TR::MemoryReference::createWithDisplacement(cg, instanceClassReg, offsetof(J9Class, castClassCache), TR::Compiler->om.sizeofReferenceAddress()));
3679
generateTrg1Src2Instruction(cg, TR::InstOpCode::Op_cmpl, node, condReg, castClassReg, castClassCacheReg);
3680
srm->reclaimScratchRegister(castClassCacheReg);
3681
3682
// At this point condReg[eq] will be set if the cast is successful. Caller is responsible for acting on the result.
3683
}
3684
3685
static
3686
void genInstanceOfOrCheckCastObjectArrayTest(TR::Node *node, TR::Register *cr0Reg, TR::Register *instanceClassReg, TR::LabelSymbol *falseLabel, TR_PPCScratchRegisterManager *srm, TR::CodeGenerator *cg)
3687
{
3688
TR::Compilation *comp = cg->comp();
3689
3690
// Load the object ROM class and test the modifiers to see if this is an array.
3691
//
3692
TR::Register *scratchReg = srm->findOrCreateScratchRegister();
3693
generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, scratchReg, TR::MemoryReference::createWithDisplacement(cg, instanceClassReg, offsetof(J9Class, romClass), TR::Compiler->om.sizeofReferenceAddress()));
3694
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, scratchReg, TR::MemoryReference::createWithDisplacement(cg, scratchReg, offsetof(J9ROMClass, modifiers), 4));
3695
if (J9AccClassArray <= UPPER_IMMED && J9AccClassArray >= LOWER_IMMED)
3696
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, scratchReg, scratchReg, cr0Reg, J9AccClassArray);
3697
else
3698
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andis_r, node, scratchReg, scratchReg, cr0Reg, J9AccClassArray >> 16);
3699
3700
// At this point cr0[eq] will be set if this is not an array.
3701
//
3702
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, falseLabel, cr0Reg);
3703
3704
// If it's an array, load the component ROM class and test the modifiers to see if this is a primitive array.
3705
//
3706
generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, scratchReg, TR::MemoryReference::createWithDisplacement(cg, instanceClassReg, offsetof(J9ArrayClass, componentType), TR::Compiler->om.sizeofReferenceAddress()));
3707
generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, scratchReg, TR::MemoryReference::createWithDisplacement(cg, scratchReg, offsetof(J9Class, romClass), TR::Compiler->om.sizeofReferenceAddress()));
3708
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, scratchReg, TR::MemoryReference::createWithDisplacement(cg, scratchReg, offsetof(J9ROMClass, modifiers), 4));
3709
if (J9AccClassInternalPrimitiveType <= UPPER_IMMED && J9AccClassInternalPrimitiveType >= LOWER_IMMED)
3710
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, scratchReg, scratchReg, cr0Reg, J9AccClassInternalPrimitiveType);
3711
else
3712
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andis_r, node, scratchReg, scratchReg, cr0Reg, J9AccClassInternalPrimitiveType >> 16);
3713
srm->reclaimScratchRegister(scratchReg);
3714
3715
// At this point cr0[eq] will be set if this is not a primitive array. Caller is responsible acting on the result.
3716
}
3717
3718
static
3719
void genInstanceOfOrCheckCastHelperCall(TR::Node *node, TR::Register *objectReg, TR::Register *castClassReg, TR::Register *resultReg, TR::CodeGenerator *cg)
3720
{
3721
TR_ASSERT((resultReg != NULL) == (node->getOpCodeValue() == TR::instanceof),
3722
"Expecting result reg for instanceof but not checkcast");
3723
3724
TR::Register *helperReturnReg = resultReg ? cg->allocateRegister() : NULL;
3725
3726
TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(1, 4, cg->trMemory());
3727
3728
deps->addPreCondition(castClassReg, TR::RealRegister::gr3);
3729
deps->addPostCondition(resultReg ? helperReturnReg : castClassReg, TR::RealRegister::gr3);
3730
deps->addPostCondition(objectReg, TR::RealRegister::gr4);
3731
TR::Register *dummyReg, *dummyRegCCR;
3732
// gr11 is killed by the trampoline.
3733
deps->addPostCondition(dummyReg = cg->allocateRegister(), TR::RealRegister::gr11);
3734
dummyReg->setPlaceholderReg();
3735
// cr0 is not preserved by the helper.
3736
deps->addPostCondition(dummyRegCCR = cg->allocateRegister(TR_CCR), TR::RealRegister::cr0);
3737
dummyRegCCR->setPlaceholderReg();
3738
3739
TR::Instruction *gcPoint = generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)node->getSymbolReference()->getMethodAddress(), deps, node->getSymbolReference());
3740
gcPoint->PPCNeedsGCMap(0xFFFFFFFF);
3741
3742
if (resultReg)
3743
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, resultReg, helperReturnReg);
3744
3745
cg->stopUsingRegister(dummyReg);
3746
cg->stopUsingRegister(dummyRegCCR);
3747
3748
cg->machine()->setLinkRegisterKilled(true);
3749
3750
TR::Register *nodeRegs[3] = {objectReg, castClassReg, resultReg};
3751
deps->stopUsingDepRegs(cg, 3, nodeRegs);
3752
}
3753
3754
TR::Register *J9::Power::TreeEvaluator::VMcheckcastEvaluator(TR::Node *node, TR::CodeGenerator *cg)
3755
{
3756
TR::Compilation *comp = cg->comp();
3757
TR_J9VMBase *fej9 = reinterpret_cast<TR_J9VMBase *>(comp->fe());
3758
TR_OpaqueClassBlock *compileTimeGuessClass;
3759
InstanceOfOrCheckCastProfiledClasses profiledClassesList[1];
3760
InstanceOfOrCheckCastSequences sequences[InstanceOfOrCheckCastMaxSequences];
3761
uint32_t numberOfProfiledClass = 0;
3762
float topClassProbability = 0.0;
3763
bool topClassWasCastClass = false;
3764
uint32_t numSequencesRemaining = calculateInstanceOfOrCheckCastSequences(node, sequences, &compileTimeGuessClass, cg, profiledClassesList, &numberOfProfiledClass, 1, &topClassProbability, &topClassWasCastClass);
3765
3766
TR::Node *objectNode = node->getFirstChild();
3767
TR::Node *castClassNode = node->getSecondChild();
3768
TR::Register *objectReg = cg->evaluate(objectNode);
3769
TR::Register *castClassReg = NULL;
3770
3771
TR::LabelSymbol *depLabel = generateLabelSymbol(cg);
3772
TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);
3773
TR::LabelSymbol *helperReturnLabel = generateLabelSymbol(cg);
3774
TR::LabelSymbol *nextSequenceLabel = generateLabelSymbol(cg);
3775
3776
TR::Instruction *gcPoint;
3777
3778
TR_PPCScratchRegisterManager *srm = cg->generateScratchRegisterManager();
3779
TR::Register *objectClassReg = NULL;
3780
TR::Register *cr0Reg = cg->allocateRegister(TR_CCR);
3781
3782
InstanceOfOrCheckCastSequences *iter = &sequences[0];
3783
while (numSequencesRemaining > 1)
3784
{
3785
switch (*iter)
3786
{
3787
case EvaluateCastClass:
3788
TR_ASSERT(!castClassReg, "Cast class already evaluated");
3789
castClassReg = cg->evaluate(castClassNode);
3790
break;
3791
case LoadObjectClass:
3792
TR_ASSERT(!objectClassReg, "Object class already loaded");
3793
objectClassReg = srm->findOrCreateScratchRegister();
3794
generateLoadJ9Class(node, objectClassReg, objectReg, cg);
3795
break;
3796
case NullTest:
3797
if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting NullTest\n", node->getOpCode().getName());
3798
TR_ASSERT(!objectNode->isNonNull(), "Object is known to be non-null, no need for a null test");
3799
if (node->getOpCodeValue() == TR::checkcastAndNULLCHK)
3800
{
3801
TR::Node *nullChkInfo = comp->findNullChkInfo(node);
3802
gcPoint = generateNullTestInstructions(cg, objectReg, nullChkInfo, !cg->getHasResumableTrapHandler());
3803
gcPoint->PPCNeedsGCMap(0x0);
3804
}
3805
else
3806
{
3807
genNullTest(node, objectReg, cr0Reg, cg);
3808
}
3809
break;
3810
case GoToTrue:
3811
TR_ASSERT(false, "Doesn't make sense, GoToTrue should not be part of multiple sequences");
3812
break;
3813
case GoToFalse:
3814
TR_ASSERT(false, "Doesn't make sense, GoToFalse should be the terminal sequence");
3815
break;
3816
case ClassEqualityTest:
3817
if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting ClassEqualityTest\n", node->getOpCode().getName());
3818
genInstanceOfOrCheckCastClassEqualityTest(node, cr0Reg, objectClassReg, castClassReg, cg);
3819
break;
3820
case SuperClassTest:
3821
{
3822
if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting SuperClassTest\n", node->getOpCode().getName());
3823
int32_t castClassDepth = castClassNode->getSymbolReference()->classDepth(comp);
3824
genInstanceOfOrCheckCastSuperClassTest(node, cr0Reg, objectClassReg, castClassReg, castClassDepth, nextSequenceLabel, srm, cg);
3825
break;
3826
}
3827
case ProfiledClassTest:
3828
if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting ProfiledClassTest\n", node->getOpCode().getName());
3829
genInstanceOfOrCheckCastArbitraryClassTest(node, cr0Reg, objectClassReg, profiledClassesList[0].profiledClass, srm, cg);
3830
break;
3831
case CompileTimeGuessClassTest:
3832
if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting CompileTimeGuessClassTest\n", node->getOpCode().getName());
3833
genInstanceOfOrCheckCastArbitraryClassTest(node, cr0Reg, objectClassReg, compileTimeGuessClass, srm, cg);
3834
break;
3835
case CastClassCacheTest:
3836
if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting CastClassCacheTest\n", node->getOpCode().getName());
3837
genCheckCastCastClassCacheTest(node, cr0Reg, objectClassReg, castClassReg, srm, cg);
3838
break;
3839
case ArrayOfJavaLangObjectTest:
3840
if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting ArrayOfJavaLangObjectTest\n", node->getOpCode().getName());
3841
genInstanceOfOrCheckCastObjectArrayTest(node, cr0Reg, objectClassReg, nextSequenceLabel, srm, cg);
3842
break;
3843
case HelperCall:
3844
TR_ASSERT(false, "Doesn't make sense, HelperCall should be the terminal sequence");
3845
break;
3846
}
3847
3848
genCheckCastTransitionToNextSequence(node, iter, nextSequenceLabel, doneLabel, cr0Reg, cg);
3849
3850
--numSequencesRemaining;
3851
++iter;
3852
3853
if (*iter != HelperCall && *iter != GoToFalse)
3854
{
3855
generateLabelInstruction(cg, TR::InstOpCode::label, node, nextSequenceLabel);
3856
nextSequenceLabel = generateLabelSymbol(cg);
3857
}
3858
}
3859
3860
if (objectClassReg)
3861
srm->reclaimScratchRegister(objectClassReg);
3862
3863
generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel);
3864
3865
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "instanceOfOrCheckCast/%s/fastPath",
3866
node->getOpCode().getName()),
3867
*srm);
3868
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "instanceOfOrCheckCast.perMethod/%s/(%s)/%d/%d/fastPath",
3869
node->getOpCode().getName(), comp->signature(), node->getByteCodeInfo().getCallerIndex(), node->getByteCodeInfo().getByteCodeIndex()),
3870
*srm);
3871
3872
TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 3 + srm->numAvailableRegisters(), cg->trMemory());
3873
srm->addScratchRegistersToDependencyList(deps, true);
3874
deps->addPostCondition(cr0Reg, TR::RealRegister::cr0);
3875
deps->addPostCondition(objectReg, TR::RealRegister::NoReg);
3876
deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();
3877
if (castClassReg)
3878
{
3879
deps->addPostCondition(castClassReg, TR::RealRegister::NoReg);
3880
deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();
3881
}
3882
3883
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, depLabel, deps);
3884
3885
generateLabelInstruction(cg, TR::InstOpCode::label, node, helperReturnLabel);
3886
3887
if (numSequencesRemaining > 0 && *iter != GoToTrue)
3888
{
3889
TR_ASSERT(*iter == HelperCall || *iter == GoToFalse, "Expecting helper call or fail here");
3890
bool helperCallForFailure = *iter != HelperCall;
3891
if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting HelperCall%s\n", node->getOpCode().getName(), helperCallForFailure ? " for failure" : "");
3892
TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::call, NULL, nextSequenceLabel, helperReturnLabel, cg);
3893
cg->generateDebugCounter(nextSequenceLabel->getInstruction(),
3894
TR::DebugCounter::debugCounterName(comp, "instanceOfOrCheckCast/%s/%s",
3895
node->getOpCode().getName(),
3896
helperCallForFailure ? "fail" : "helperCall"));
3897
cg->generateDebugCounter(nextSequenceLabel->getInstruction(),
3898
TR::DebugCounter::debugCounterName(comp, "instanceOfOrCheckCast.perMethod/%s/(%s)/%d/%d/%s",
3899
node->getOpCode().getName(), comp->signature(), node->getByteCodeInfo().getCallerIndex(), node->getByteCodeInfo().getByteCodeIndex(),
3900
helperCallForFailure ? "fail" : "helperCall"));
3901
3902
cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);
3903
}
3904
3905
deps->stopUsingDepRegs(cg, objectReg, castClassReg);
3906
cg->decReferenceCount(objectNode);
3907
cg->decReferenceCount(castClassNode);
3908
3909
return NULL;
3910
}
3911
3912
TR::Register *J9::Power::TreeEvaluator::VMinstanceOfEvaluator(TR::Node *node, TR::CodeGenerator *cg)
3913
{
3914
TR::Compilation *comp = cg->comp();
3915
TR_OpaqueClassBlock *compileTimeGuessClass;
3916
bool profiledClassIsInstanceOf;
3917
InstanceOfOrCheckCastProfiledClasses profiledClassesList[1];
3918
InstanceOfOrCheckCastSequences sequences[InstanceOfOrCheckCastMaxSequences];
3919
bool topClassWasCastClass = false;
3920
float topClassProbability = 0.0;
3921
uint32_t numberOfProfiledClass;
3922
uint32_t numSequencesRemaining = calculateInstanceOfOrCheckCastSequences(node, sequences, &compileTimeGuessClass, cg, profiledClassesList, &numberOfProfiledClass, 1, &topClassProbability, &topClassWasCastClass);
3923
3924
TR::Node *objectNode = node->getFirstChild();
3925
TR::Node *castClassNode = node->getSecondChild();
3926
TR::Register *objectReg = cg->evaluate(objectNode);
3927
TR::Register *castClassReg = NULL;
3928
TR::Register *resultReg = cg->allocateRegister();
3929
3930
TR::LabelSymbol *depLabel = generateLabelSymbol(cg);
3931
TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);
3932
TR::LabelSymbol *helperReturnLabel = generateLabelSymbol(cg);
3933
TR::LabelSymbol *nextSequenceLabel = generateLabelSymbol(cg);
3934
TR::LabelSymbol *oppositeResultLabel = generateLabelSymbol(cg);
3935
3936
TR::Instruction *gcPoint;
3937
3938
TR_PPCScratchRegisterManager *srm = cg->generateScratchRegisterManager();
3939
TR::Register *objectClassReg = NULL;
3940
TR::Register *cr0Reg = cg->allocateRegister(TR_CCR);
3941
3942
static bool initialResult = feGetEnv("TR_instanceOfInitialValue") != NULL;//true;
3943
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, initialResult);
3944
3945
InstanceOfOrCheckCastSequences *iter = &sequences[0];
3946
while (numSequencesRemaining > 1 || (numSequencesRemaining == 1 && *iter != HelperCall))
3947
{
3948
switch (*iter)
3949
{
3950
case EvaluateCastClass:
3951
TR_ASSERT(!castClassReg, "Cast class already evaluated");
3952
castClassReg = cg->evaluate(castClassNode);
3953
break;
3954
case LoadObjectClass:
3955
TR_ASSERT(!objectClassReg, "Object class already loaded");
3956
objectClassReg = srm->findOrCreateScratchRegister();
3957
generateLoadJ9Class(node, objectClassReg, objectReg, cg);
3958
break;
3959
case NullTest:
3960
if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting NullTest\n", node->getOpCode().getName());
3961
TR_ASSERT(!objectNode->isNonNull(), "Object is known to be non-null, no need for a null test");
3962
if (node->getOpCodeValue() == TR::checkcastAndNULLCHK)
3963
{
3964
TR::Node *nullChkInfo = comp->findNullChkInfo(node);
3965
gcPoint = generateNullTestInstructions(cg, objectReg, nullChkInfo, !cg->getHasResumableTrapHandler());
3966
gcPoint->PPCNeedsGCMap(0x0);
3967
}
3968
else
3969
{
3970
genNullTest(node, objectReg, cr0Reg, cg);
3971
}
3972
break;
3973
case GoToTrue:
3974
if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting GoToTrue\n", node->getOpCode().getName());
3975
if (initialResult == true)
3976
generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);
3977
break;
3978
case GoToFalse:
3979
if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting GoToFalse\n", node->getOpCode().getName());
3980
if (initialResult == false)
3981
generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);
3982
break;
3983
case ClassEqualityTest:
3984
if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting ClassEqualityTest\n", node->getOpCode().getName());
3985
genInstanceOfOrCheckCastClassEqualityTest(node, cr0Reg, objectClassReg, castClassReg, cg);
3986
break;
3987
case SuperClassTest:
3988
{
3989
if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting SuperClassTest\n", node->getOpCode().getName());
3990
int32_t castClassDepth = castClassNode->getSymbolReference()->classDepth(comp);
3991
genInstanceOfOrCheckCastSuperClassTest(node, cr0Reg, objectClassReg, castClassReg, castClassDepth, nextSequenceLabel, srm, cg);
3992
break;
3993
}
3994
case ProfiledClassTest:
3995
if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting ProfiledClassTest\n", node->getOpCode().getName());
3996
profiledClassIsInstanceOf = profiledClassesList[0].isProfiledClassInstanceOfCastClass;
3997
genInstanceOfOrCheckCastArbitraryClassTest(node, cr0Reg, objectClassReg, profiledClassesList[0].profiledClass, srm, cg);
3998
break;
3999
case CompileTimeGuessClassTest:
4000
if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting CompileTimeGuessClassTest\n", node->getOpCode().getName());
4001
genInstanceOfOrCheckCastArbitraryClassTest(node, cr0Reg, objectClassReg, compileTimeGuessClass, srm, cg);
4002
break;
4003
case CastClassCacheTest:
4004
if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting CastClassCacheTest\n", node->getOpCode().getName());
4005
genInstanceOfCastClassCacheTest(node, cr0Reg, objectClassReg, castClassReg, srm, cg);
4006
break;
4007
case ArrayOfJavaLangObjectTest:
4008
if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting ArrayOfJavaLangObjectTest\n", node->getOpCode().getName());
4009
genInstanceOfOrCheckCastObjectArrayTest(node, cr0Reg, objectClassReg, nextSequenceLabel, srm, cg);
4010
break;
4011
case DynamicCacheObjectClassTest:
4012
TR_ASSERT_FATAL(false, "%s: DynamicCacheObjectClassTest is not implemented on P\n", node->getOpCode().getName());
4013
break;
4014
case DynamicCacheDynamicCastClassTest:
4015
TR_ASSERT_FATAL(false, "%s: DynamicCacheDynamicCastClassTest is not implemented on P\n", node->getOpCode().getName());
4016
break;
4017
case HelperCall:
4018
TR_ASSERT(false, "Doesn't make sense, HelperCall should be the terminal sequence");
4019
break;
4020
}
4021
4022
genInstanceOfTransitionToNextSequence(node, iter, nextSequenceLabel, doneLabel, cr0Reg, resultReg, initialResult, oppositeResultLabel, profiledClassIsInstanceOf, cg);
4023
4024
--numSequencesRemaining;
4025
++iter;
4026
4027
if (*iter != HelperCall)
4028
{
4029
generateLabelInstruction(cg, TR::InstOpCode::label, node, nextSequenceLabel);
4030
nextSequenceLabel = generateLabelSymbol(cg);
4031
}
4032
}
4033
4034
if (objectClassReg)
4035
srm->reclaimScratchRegister(objectClassReg);
4036
4037
if (true)
4038
{
4039
generateLabelInstruction(cg, TR::InstOpCode::label, node, oppositeResultLabel);
4040
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, !initialResult);
4041
}
4042
4043
generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel);
4044
4045
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "instanceOfOrCheckCast/%s/fastPath",
4046
node->getOpCode().getName()),
4047
*srm);
4048
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "instanceOfOrCheckCast.perMethod/%s/(%s)/%d/%d/fastPath",
4049
node->getOpCode().getName(), comp->signature(), node->getByteCodeInfo().getCallerIndex(), node->getByteCodeInfo().getByteCodeIndex()),
4050
*srm);
4051
4052
TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 4 + srm->numAvailableRegisters(), cg->trMemory());
4053
srm->addScratchRegistersToDependencyList(deps, true);
4054
deps->addPostCondition(cr0Reg, TR::RealRegister::cr0);
4055
deps->addPostCondition(resultReg, TR::RealRegister::NoReg);
4056
deps->addPostCondition(objectReg, TR::RealRegister::NoReg);
4057
deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();
4058
if (castClassReg)
4059
{
4060
deps->addPostCondition(castClassReg, TR::RealRegister::NoReg);
4061
deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();
4062
}
4063
4064
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, depLabel, deps);
4065
4066
generateLabelInstruction(cg, TR::InstOpCode::label, node, helperReturnLabel);
4067
4068
if (numSequencesRemaining > 0)
4069
{
4070
if (*iter == HelperCall)
4071
{
4072
if (comp->getOption(TR_TraceCG)) traceMsg(comp, "%s: Emitting HelperCall\n", node->getOpCode().getName());
4073
TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::icall, resultReg, nextSequenceLabel, helperReturnLabel, cg);
4074
cg->generateDebugCounter(nextSequenceLabel->getInstruction(),
4075
TR::DebugCounter::debugCounterName(comp, "instanceOfOrCheckCast/%s/helperCall",
4076
node->getOpCode().getName()));
4077
cg->generateDebugCounter(nextSequenceLabel->getInstruction(),
4078
TR::DebugCounter::debugCounterName(comp, "instanceOfOrCheckCast.perMethod/%s/(%s)/%d/%d/helperCall",
4079
node->getOpCode().getName(), comp->signature(), node->getByteCodeInfo().getCallerIndex(), node->getByteCodeInfo().getByteCodeIndex()));
4080
4081
cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);
4082
}
4083
}
4084
4085
// Stop using every reg in the deps except these ones.
4086
//
4087
TR::Register *nodeRegs[3] = {objectReg, castClassReg, resultReg};
4088
deps->stopUsingDepRegs(cg, 3, nodeRegs);
4089
4090
cg->decReferenceCount(objectNode);
4091
cg->decReferenceCount(castClassNode);
4092
4093
node->setRegister(resultReg);
4094
4095
return resultReg;
4096
}
4097
4098
// ----------------------------------------------------------------------------
4099
4100
// only need a helper call if the class is not super and not final, otherwise
4101
// it can be determined without a call-out
4102
static bool needHelperCall(bool testCastClassIsSuper, bool isFinalClass)
4103
{
4104
return !testCastClassIsSuper && !isFinalClass;
4105
}
4106
4107
static bool needTestCache(bool cachingEnabled, bool needsHelperCall, bool superClassTest, TR_OpaqueClassBlock* castClassAddr, uint8_t num_PICS)
4108
{
4109
return cachingEnabled && needsHelperCall && !superClassTest && castClassAddr && num_PICS;
4110
}
4111
4112
TR::Register *J9::Power::TreeEvaluator::ifInstanceOfEvaluator(TR::Node *node, TR::CodeGenerator *cg)
4113
{
4114
return TR::TreeEvaluator::VMifInstanceOfEvaluator(node, cg);
4115
}
4116
4117
4118
TR::Register *J9::Power::TreeEvaluator::VMifInstanceOfEvaluator(TR::Node *node, TR::CodeGenerator *cg)
4119
{
4120
TR::Node *depNode;
4121
int32_t depIndex;
4122
int32_t numDep;
4123
TR::LabelSymbol *branchLabel;
4124
TR::Node *instanceOfNode;
4125
TR::Node *valueNode;
4126
int32_t value;
4127
TR::LabelSymbol *doneLabel, *res0Label, *res1Label;
4128
bool branchOn1;
4129
TR::Register *resultReg;
4130
TR::ILOpCodes opCode;
4131
TR::Compilation * comp = cg->comp();
4132
TR::SymbolReference *castClassSymRef;
4133
TR::Node *castClassNode;
4134
TR_OpaqueClassBlock *castClassAddr;
4135
TR_OpaqueClassBlock *guessClassArray[NUM_PICS];
4136
4137
depIndex = 0;
4138
numDep = 0;
4139
depNode = NULL;
4140
branchLabel = node->getBranchDestination()->getNode()->getLabel();
4141
instanceOfNode = node->getFirstChild();
4142
valueNode = node->getSecondChild();
4143
value = valueNode->getInt();
4144
opCode = node->getOpCodeValue();
4145
4146
castClassNode = instanceOfNode->getSecondChild();
4147
castClassSymRef = castClassNode->getSymbolReference();
4148
castClassAddr = TR::TreeEvaluator::getCastClassAddress(castClassNode);
4149
uint8_t num_PICS = TR::TreeEvaluator::interpreterProfilingInstanceOfOrCheckCastInfo(cg, instanceOfNode, guessClassArray);
4150
4151
bool testEqualClass = instanceOfOrCheckCastNeedEqualityTest(instanceOfNode, cg);
4152
// Testing castClassAddr to set testCastClassIsSuper only if cast class is known at compile time
4153
// When class is unknown, testCastClassIsSuper is false, and needsHelperCall is true to handle non-typical class types (e.g. interfaces)
4154
bool testCastClassIsSuper = castClassAddr && instanceOfOrCheckCastNeedSuperTest(instanceOfNode, cg);
4155
bool isFinalClass = (castClassSymRef == NULL) ? false : castClassSymRef->isNonArrayFinal(comp);
4156
bool needsHelperCall = needHelperCall(testCastClassIsSuper, isFinalClass);
4157
bool testCache = needTestCache(!comp->getOption(TR_DisableInlineCheckCast), needsHelperCall, testCastClassIsSuper, castClassAddr, num_PICS);
4158
4159
if (node->getNumChildren() == 3)
4160
{
4161
depNode = node->getChild(2);
4162
numDep = depNode->getNumChildren();
4163
}
4164
4165
// If the result itself is assigned to a global register, we still have to evaluate it
4166
int32_t needResult = (instanceOfNode->getReferenceCount() > 1);
4167
4168
if (depNode != NULL)
4169
{
4170
int32_t i1;
4171
4172
if (!needsHelperCall && numberOfRegisterCandidate(cg, depNode, TR_GPR) + 7 > cg->getMaximumNumberOfGPRsAllowedAcrossEdge(node))
4173
return ((TR::Register *) 1);
4174
4175
const TR::PPCLinkageProperties& properties = cg->getLinkage()->getProperties();
4176
TR::Node *objNode = instanceOfNode->getFirstChild();
4177
for (i1 = 0; i1 < depNode->getNumChildren(); i1++)
4178
{
4179
TR::Node *childNode = depNode->getChild(i1);
4180
int32_t regIndex = cg->getGlobalRegister(childNode->getGlobalRegisterNumber());
4181
4182
int32_t validHighRegNum = TR::TreeEvaluator::getHighGlobalRegisterNumberIfAny(childNode, cg);
4183
4184
if (needsHelperCall)
4185
{
4186
int32_t highIndex;
4187
4188
if (validHighRegNum != -1)
4189
highIndex = cg->getGlobalRegister(validHighRegNum);
4190
4191
if (!properties.getPreserved((TR::RealRegister::RegNum) regIndex)
4192
|| (validHighRegNum != -1 && !properties.getPreserved((TR::RealRegister::RegNum) highIndex)))
4193
return ((TR::Register *) 1);
4194
}
4195
else
4196
{
4197
if (childNode->getOpCodeValue() == TR::PassThrough)
4198
childNode = childNode->getFirstChild();
4199
if ((childNode == objNode || childNode == castClassNode) && regIndex == TR::RealRegister::gr0)
4200
return ((TR::Register *) 1);
4201
}
4202
}
4203
depIndex = numberOfRegisterCandidate(cg, depNode, TR_GPR) + numberOfRegisterCandidate(cg, depNode, TR_FPR) +
4204
numberOfRegisterCandidate(cg, depNode, TR_CCR) + numberOfRegisterCandidate(cg, depNode, TR_VRF) +
4205
numberOfRegisterCandidate(cg, depNode, TR_VSX_SCALAR) + numberOfRegisterCandidate(cg, depNode, TR_VSX_VECTOR);
4206
}
4207
4208
doneLabel = generateLabelSymbol(cg);
4209
4210
if ((opCode == TR::ificmpeq && value == 1) || (opCode != TR::ificmpeq && value == 0))
4211
{
4212
res0Label = doneLabel;
4213
res1Label = branchLabel;
4214
branchOn1 = true;
4215
}
4216
else
4217
{
4218
res0Label = branchLabel;
4219
res1Label = doneLabel;
4220
branchOn1 = false;
4221
}
4222
4223
resultReg = TR::TreeEvaluator::VMgenCoreInstanceofEvaluator(instanceOfNode, cg, true, depIndex, numDep, depNode, needResult, needsHelperCall, testEqualClass, testCache, testCastClassIsSuper,
4224
doneLabel, res0Label, res1Label, branchOn1);
4225
4226
if (resultReg != instanceOfNode->getRegister())
4227
instanceOfNode->setRegister(resultReg);
4228
cg->decReferenceCount(instanceOfNode);
4229
cg->decReferenceCount(valueNode);
4230
4231
node->setRegister(NULL);
4232
return NULL;
4233
}
4234
4235
// genCoreInstanceofEvaluator is used by if instanceof and instanceof routines.
4236
// The routine generates the 'core' code for instanceof evaluation. It requires a true and false label
4237
// (which are the same and are just fall-through labels if no branching is required) as well as
4238
// a boolean to indicate if the result should be calculated and returned in a register.
4239
// The code also needs to indicate if the fall-through case if for 'true' or 'false'.
4240
TR::Register * J9::Power::TreeEvaluator::VMgenCoreInstanceofEvaluator(TR::Node * node, TR::CodeGenerator * cg, bool isVMifInstanceOf, int32_t depIndex, int32_t numDep,
4241
TR::Node *depNode, bool needResult, bool needHelperCall, bool testEqualClass, bool testCache, bool testCastClassIsSuper, TR::LabelSymbol *doneLabel,
4242
TR::LabelSymbol *res0Label, TR::LabelSymbol *res1Label, bool branchOn1)
4243
{
4244
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
4245
TR::Register *objectReg, *castClassReg, *objClassReg;
4246
TR::Register *resultReg, *crReg, *scratch1Reg, *scratch2Reg, *scratch3Reg;
4247
TR::Instruction *iCursor;
4248
TR::SymbolReference *castClassSymRef;
4249
TR::RegisterDependencyConditions *conditions;
4250
TR::LabelSymbol *trueLabel, *callLabel, *nextTestLabel;
4251
TR::Node *objectNode, *castClassNode;
4252
int32_t castClassDepth;
4253
TR::ILOpCodes opCode;
4254
TR::RegisterDependencyConditions *deps;
4255
TR_OpaqueClassBlock *castClassAddr;
4256
TR_OpaqueClassBlock *guessClassArray[NUM_PICS];
4257
TR::Compilation * comp = cg->comp();
4258
castClassDepth = -1;
4259
trueLabel = NULL;
4260
resultReg = NULL;
4261
deps = NULL;
4262
iCursor = NULL;
4263
4264
castClassNode = node->getSecondChild();
4265
castClassSymRef = castClassNode->getSymbolReference();
4266
castClassAddr = TR::TreeEvaluator::getCastClassAddress(castClassNode);
4267
uint8_t num_PICS = TR::TreeEvaluator::interpreterProfilingInstanceOfOrCheckCastInfo(cg, node, guessClassArray);
4268
objectNode = node->getFirstChild();
4269
4270
bool stopUsingHelperCallCR = false;
4271
4272
if (needHelperCall)
4273
{
4274
callLabel = generateLabelSymbol(cg);
4275
4276
TR::ILOpCodes opCode = node->getOpCodeValue();
4277
4278
TR::Node::recreate(node, TR::icall);
4279
directCallEvaluator(node, cg);
4280
TR::Node::recreate(node, opCode);
4281
4282
iCursor = cg->getAppendInstruction();
4283
while (iCursor->getOpCodeValue() != TR::InstOpCode::bl)
4284
iCursor = iCursor->getPrev();
4285
conditions = ((TR::PPCDepImmSymInstruction *) iCursor)->getDependencyConditions();
4286
iCursor = iCursor->getPrev();
4287
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, callLabel, iCursor);
4288
iCursor = iCursor->getPrev();
4289
4290
auto firstArgReg = node->getSymbol()->castToMethodSymbol()->getLinkageConvention() == TR_CHelper ? TR::RealRegister::gr4 : TR::RealRegister::gr3;
4291
objectReg = conditions->searchPreConditionRegister(static_cast<TR::RealRegister::RegNum>(firstArgReg + 1));
4292
castClassReg = conditions->searchPreConditionRegister(firstArgReg);
4293
scratch1Reg = conditions->searchPreConditionRegister(static_cast<TR::RealRegister::RegNum>(firstArgReg + 2));
4294
scratch2Reg = conditions->searchPreConditionRegister(static_cast<TR::RealRegister::RegNum>(firstArgReg + 4));
4295
scratch3Reg = conditions->searchPreConditionRegister(static_cast<TR::RealRegister::RegNum>(firstArgReg + 6));
4296
objClassReg = conditions->searchPreConditionRegister(static_cast<TR::RealRegister::RegNum>(firstArgReg + 3));
4297
crReg = conditions->searchPreConditionRegister(TR::RealRegister::cr0);
4298
if (!crReg)
4299
{
4300
// This is another hack to compensate for skipping the preserving of CCRs for helper calls in linkage code.
4301
// This hack wouldn't be necessary if this code wasn't being lazy and re-using the dependencies
4302
// set up by the direct call evaluator, but alas...
4303
// Since we are not preserving CCRs and this code previously expected to find a CCR in the call instruction's
4304
// dependency conditions we allocate a new virtual here and stick it in the dependencies, making sure to
4305
// repeat everything that is normally done for virtual regs when they are referenced by a generated instruction,
4306
// which just means we record two uses to correspond to the fact that we added them to the pre/post deps of the
4307
// call.
4308
crReg = nonFixedDependency(conditions, NULL, &depIndex, TR_CCR, false, cg);
4309
stopUsingHelperCallCR = true;
4310
TR::Instruction *callInstruction = scratch1Reg->getStartOfRange();
4311
callInstruction->useRegister(crReg);
4312
callInstruction->useRegister(crReg);
4313
}
4314
4315
if (depNode != NULL)
4316
{
4317
cg->evaluate(depNode);
4318
deps = generateRegisterDependencyConditions(cg, depNode, 0, &iCursor);
4319
}
4320
4321
if (testEqualClass || testCache || testCastClassIsSuper)
4322
{
4323
if (needResult)
4324
{
4325
resultReg = conditions->searchPreConditionRegister(static_cast<TR::RealRegister::RegNum>(firstArgReg + 5));
4326
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 0, iCursor);
4327
}
4328
if (!objectNode->isNonNull())
4329
{
4330
iCursor = genNullTest(objectNode, objectReg, crReg, scratch1Reg, iCursor, cg);
4331
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, res0Label, crReg, iCursor);
4332
}
4333
}
4334
}
4335
else
4336
{
4337
bool earlyEval = (castClassNode->getOpCodeValue() != TR::loadaddr || castClassNode->getReferenceCount() > 1) ? true : false;
4338
4339
bool objInDep = false, castClassInDep = false;
4340
if (depNode != NULL)
4341
{
4342
int32_t i1;
4343
4344
TR::Node *grNode;
4345
cg->evaluate(depNode);
4346
deps = generateRegisterDependencyConditions(cg, depNode, 7);
4347
4348
for (i1 = 0; i1 < numDep; i1++)
4349
{
4350
grNode = depNode->getChild(i1);
4351
if (grNode->getOpCodeValue() == TR::PassThrough)
4352
grNode = grNode->getFirstChild();
4353
if (grNode == objectNode)
4354
objInDep = true;
4355
if (grNode == castClassNode)
4356
castClassInDep = true;
4357
}
4358
}
4359
4360
if (deps == NULL)
4361
{
4362
conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(7, 7, cg->trMemory());
4363
}
4364
else
4365
{
4366
conditions = deps;
4367
}
4368
4369
crReg = nonFixedDependency(conditions, NULL, &depIndex, TR_CCR, false, cg);
4370
4371
if (needResult)
4372
resultReg = nonFixedDependency(conditions, NULL, &depIndex, TR_GPR, false, cg);
4373
4374
objClassReg = nonFixedDependency(conditions, NULL, &depIndex, TR_GPR, true, cg);
4375
4376
objectReg = cg->evaluate(objectNode);
4377
4378
if (!objInDep)
4379
objectReg = nonFixedDependency(conditions, objectReg, &depIndex, TR_GPR, true, cg);
4380
4381
if (earlyEval)
4382
{
4383
castClassReg = cg->evaluate(castClassNode);
4384
castClassReg = nonFixedDependency(conditions, castClassReg, &depIndex, TR_GPR, true, cg);
4385
}
4386
4387
if (needResult)
4388
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 0);
4389
4390
if (!objectNode->isNonNull())
4391
{
4392
genNullTest(objectNode, objectReg, crReg, objClassReg, NULL, cg);
4393
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, res0Label, crReg);
4394
}
4395
4396
if (!earlyEval)
4397
{
4398
castClassReg = cg->evaluate(castClassNode);
4399
castClassReg = nonFixedDependency(conditions, castClassReg, &depIndex, TR_GPR, true, cg);
4400
}
4401
4402
if (testCastClassIsSuper)
4403
{
4404
scratch1Reg = nonFixedDependency(conditions, NULL, &depIndex, TR_GPR, true, cg);
4405
scratch2Reg = nonFixedDependency(conditions, NULL, &depIndex, TR_GPR, true, cg);
4406
cg->stopUsingRegister(scratch1Reg);
4407
cg->stopUsingRegister(scratch2Reg);
4408
}
4409
4410
iCursor = cg->getAppendInstruction();
4411
4412
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);
4413
4414
cg->decReferenceCount(objectNode);
4415
cg->decReferenceCount(castClassNode);
4416
cg->stopUsingRegister(crReg);
4417
cg->stopUsingRegister(objClassReg);
4418
}
4419
4420
if (testEqualClass || testCache || testCastClassIsSuper)
4421
{
4422
if (TR::Compiler->om.compressObjectReferences())
4423
// read only 32 bits
4424
iCursor = generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, objClassReg,
4425
TR::MemoryReference::createWithDisplacement(cg, objectReg,
4426
(int32_t) TR::Compiler->om.offsetOfObjectVftField(), 4),
4427
iCursor);
4428
else
4429
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, objClassReg,
4430
TR::MemoryReference::createWithDisplacement(cg, objectReg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
4431
iCursor = TR::TreeEvaluator::generateVFTMaskInstruction(cg, node, objClassReg, iCursor);
4432
}
4433
4434
if (testEqualClass)
4435
{
4436
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, crReg, objClassReg, castClassReg, iCursor);
4437
4438
if (testCache || testCastClassIsSuper)
4439
{
4440
if (needResult)
4441
{
4442
trueLabel = generateLabelSymbol(cg);
4443
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, trueLabel, crReg, iCursor);
4444
}
4445
else
4446
{
4447
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, res1Label, crReg, iCursor);
4448
}
4449
}
4450
else if (needHelperCall)
4451
{
4452
if (needResult)
4453
{
4454
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1, iCursor);
4455
}
4456
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, res1Label, crReg, iCursor);
4457
4458
bool castClassIsReferenceArray = (comp->isOptServer()) && (!castClassNode->getSymbolReference()->isUnresolved())
4459
&& (castClassNode->getSymbolReference() == comp->getSymRefTab()->findVftSymbolRef()) && (castClassNode->getNumChildren() == 1)
4460
&& (castClassNode->getFirstChild()->getOpCodeValue() == TR::anewarray);
4461
if (castClassIsReferenceArray)
4462
{
4463
TR_OpaqueClassBlock * jlobjectclassBlock = fej9->getSystemClassFromClassName("java/lang/Object", 16);
4464
J9Class* jlobjectarrayclassBlock = jlobjectclassBlock ? (J9Class*)fej9->getArrayClassFromComponentClass((TR_OpaqueClassBlock*)jlobjectclassBlock) : NULL;
4465
if (jlobjectarrayclassBlock != NULL)
4466
{
4467
iCursor = loadAddressConstant(cg, comp->compileRelocatableCode(), node, (intptr_t) (jlobjectarrayclassBlock), scratch1Reg, iCursor);
4468
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, crReg, objClassReg, scratch1Reg, iCursor);
4469
if (needResult)
4470
{
4471
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 0, iCursor);
4472
}
4473
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, res0Label, crReg, iCursor);
4474
}
4475
}
4476
}
4477
else
4478
{
4479
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, res0Label, crReg, iCursor);
4480
if (needResult)
4481
{
4482
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1, iCursor);
4483
}
4484
4485
if (branchOn1)
4486
{
4487
iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, res1Label, iCursor);
4488
}
4489
}
4490
}
4491
4492
if (testCache)
4493
{
4494
// The cached value could have been from a previously successful checkcast or instanceof.
4495
// An answer of 0 in the low order bit indicates 'success' (the cast or instanceof was successful).
4496
// An answer of 1 in the lower order bit indicates 'failure' (the cast would have thrown an exception, instanceof would have been unsuccessful)
4497
// Because of this, we can just do a simple load and compare of the 2 class pointers. If it succeeds, the low order bit
4498
// must be off (success) from a previous checkcast or instanceof. If the low order bit is on, it is guaranteed not to
4499
// compare and we will take the slow path.
4500
// Generate inline test for instanceOf
4501
genInlineTest(node, castClassAddr, guessClassArray, num_PICS, objClassReg, resultReg, crReg, scratch1Reg, scratch2Reg, false, needResult, res0Label, res1Label, doneLabel,
4502
callLabel, testCastClassIsSuper, iCursor, cg);
4503
}
4504
4505
if (testCastClassIsSuper)
4506
{
4507
bool depthInReg2 = false;
4508
4509
TR::StaticSymbol *castClassSym = NULL;
4510
if (castClassSymRef && !castClassSymRef->isUnresolved())
4511
castClassSym = castClassSymRef->getSymbol()->getStaticSymbol();
4512
4513
TR_OpaqueClassBlock * clazz = NULL;
4514
if (castClassSym)
4515
clazz = (TR_OpaqueClassBlock *) castClassSym->getStaticAddress();
4516
4517
if(clazz)
4518
castClassDepth = (int32_t)TR::Compiler->cls.classDepthOf(clazz);
4519
4520
if (castClassDepth == -1)
4521
{
4522
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, scratch2Reg,
4523
TR::MemoryReference::createWithDisplacement(cg, castClassReg, offsetof(J9Class, classDepthAndFlags), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
4524
iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, scratch2Reg, scratch2Reg, 0, J9AccClassDepthMask, iCursor);
4525
depthInReg2 = true;
4526
}
4527
4528
iCursor = genTestIsSuper(node, objClassReg, castClassReg, crReg, scratch1Reg, scratch2Reg, castClassDepth, res0Label, iCursor, cg, depthInReg2);
4529
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, res0Label, crReg, iCursor);
4530
4531
if (trueLabel == NULL)
4532
{
4533
if (needResult)
4534
{
4535
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1, iCursor);
4536
}
4537
}
4538
else
4539
{
4540
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, trueLabel, iCursor);
4541
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1, iCursor);
4542
}
4543
4544
if (branchOn1)
4545
{
4546
iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, res1Label, iCursor);
4547
}
4548
}
4549
else if (testCache)
4550
{
4551
if (trueLabel == NULL)
4552
{
4553
if (needResult)
4554
{
4555
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1, iCursor);
4556
}
4557
}
4558
else
4559
{
4560
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, trueLabel, iCursor);
4561
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1, iCursor);
4562
}
4563
}
4564
4565
if (needHelperCall)
4566
{
4567
TR::Register *callResult = node->getRegister();
4568
TR::RegisterDependencyConditions *newDeps;
4569
4570
if (resultReg == NULL)
4571
{
4572
resultReg = callResult;
4573
}
4574
else
4575
{
4576
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, resultReg, callResult);
4577
}
4578
4579
if (isVMifInstanceOf)
4580
{
4581
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, crReg, resultReg, 0);
4582
}
4583
4584
if (depNode != NULL)
4585
{
4586
newDeps = conditions->cloneAndFix(cg, deps);
4587
}
4588
else
4589
{
4590
newDeps = conditions->cloneAndFix(cg);
4591
}
4592
4593
if (isVMifInstanceOf)
4594
{
4595
if (branchOn1)
4596
{
4597
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, res1Label, crReg);
4598
}
4599
else
4600
{
4601
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, res0Label, crReg);
4602
}
4603
}
4604
4605
// Just fall through
4606
// generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);
4607
4608
// Done
4609
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, newDeps);
4610
4611
if (stopUsingHelperCallCR)
4612
cg->stopUsingRegister(crReg);
4613
4614
// We have to revive the resultReg here. Should revisit to see how to use registers better
4615
// (e.g., reducing the chance of moving around).
4616
if (resultReg != callResult)
4617
reviveResultRegister(resultReg, callResult, cg);
4618
}
4619
4620
if (depNode != NULL)
4621
cg->decReferenceCount(depNode);
4622
4623
return resultReg;
4624
}
4625
4626
static TR::Register *
4627
reservationLockEnter(TR::Node *node, int32_t lwOffset, TR::CodeGenerator *cg, TR::RegisterDependencyConditions *conditions, TR::Register *objReg, TR::Register *monitorReg, TR::Register *valReg, TR::Register *tempReg, TR::Register *cndReg, TR::LabelSymbol *callLabel)
4628
{
4629
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
4630
TR::LabelSymbol *resLabel, *doneLabel, *doneOOLLabel, *loopLabel, *reserved_checkLabel;
4631
int32_t lockSize;
4632
TR::Compilation * comp = cg->comp();
4633
4634
TR::Register *metaReg = cg->getMethodMetaDataRegister();
4635
4636
resLabel = generateLabelSymbol(cg);
4637
loopLabel = generateLabelSymbol(cg);
4638
reserved_checkLabel = generateLabelSymbol(cg);
4639
doneLabel = generateLabelSymbol(cg);
4640
doneOOLLabel = generateLabelSymbol(cg);
4641
4642
TR::TreeEvaluator::isPrimitiveMonitor(node, cg);
4643
bool isPrimitive = node->isPrimitiveLockedRegion();
4644
lockSize = comp->target().is64Bit() && !fej9->generateCompressedLockWord() ? 8 : 4;
4645
4646
/*
4647
* PRIMITIVE lockReservation enter sequence: Non-Primitive lockReservation enter sequence:
4648
* ld/lwz monitorReg, lwOffset(objReg) ld/lwz monitorReg, lwOffset(objReg)
4649
* ori valReg, metaReg, LOCK_RESERVATION_BIT ori valReg, metaReg, LOCK_RESERVATION_BIT
4650
* cmpl cr0, monitorReg, valReg cmpl cr0, monitorReg, valReg
4651
* beq doneLabel bne resLabel <--- Diff
4652
* addi tempReg, monitorReg, LOCK_INC_DEC_VALUE <--- Diff
4653
* st tempReg, lwOffset(objReg) <--- Diff
4654
* b doneLabel
4655
* resLabel(startOOLLabel):
4656
* cmpli cr0, monitorReg, 0 cmpli cr0, monitorReg, 0
4657
* bne reserved_checkLabel bne reserved_checkLabel
4658
* li tempReg, lwOffset li tempReg, lwOffset
4659
* addi valReg, metaReg, RES+INC <--- Diff
4660
* loopLabel:
4661
* larx monitorReg, [objReg, tempReg] larx monitorReg, [objReg, tempReg]
4662
* cmpli cr0, monitorReg, 0 cmpli cr0, monitorReg, 0
4663
* bne callLabel bne callLabel
4664
* stcx. valReg, [objReg, tempReg] stcx. valReg, [objReg, tempReg]
4665
* bne loopLabel bne loopLabel
4666
* isync isync
4667
* b doneLabel b doneLabel
4668
* reserved_checkLabel:
4669
* li tempReg, PRIMITIVE_ENTER_MASK li tempReg, NON_PRIMITIVE_ENTER_MASK <--- Diff
4670
* andc tempReg, monitorReg, tempReg andc tempReg, monitorReg, tempReg
4671
* addi valReg, metaReg, RES <--- Diff
4672
* cmpl cr0, tempReg, valReg cmpl cr0, tempReg, valReg
4673
* bne callLabel bne callLabel
4674
* addi monitorReg, monitorReg, INC <--- Diff
4675
* st monitorReg, [objReg, lwOffset] <--- Diff
4676
* doneLabel:
4677
* doneOOLLabel:
4678
* === OUT OF LINE ===
4679
* callLabel:
4680
* bl jitMonitorEntry
4681
* b doneOOLLabel
4682
*/
4683
4684
generateTrg1MemInstruction(cg, lockSize == 8 ? TR::InstOpCode::ld : TR::InstOpCode::lwz, node, monitorReg, TR::MemoryReference::createWithDisplacement(cg, objReg, lwOffset, lockSize));
4685
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, valReg, metaReg, LOCK_RESERVATION_BIT);
4686
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, monitorReg, valReg);
4687
4688
if (!isPrimitive)
4689
{
4690
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, resLabel, cndReg);
4691
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tempReg, monitorReg, LOCK_INC_DEC_VALUE);
4692
generateMemSrc1Instruction(cg, lockSize == 8 ? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, objReg, lwOffset, lockSize), tempReg);
4693
generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);
4694
}
4695
else
4696
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, cndReg);
4697
4698
generateLabelInstruction(cg, TR::InstOpCode::label, node, resLabel);
4699
generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, cndReg, monitorReg, 0);
4700
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, reserved_checkLabel, cndReg);
4701
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tempReg, lwOffset);
4702
if (!isPrimitive)
4703
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, valReg, metaReg, LOCK_RESERVATION_BIT | LOCK_INC_DEC_VALUE);
4704
generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);
4705
generateTrg1MemInstruction(cg, lockSize == 8 ? TR::InstOpCode::ldarx : TR::InstOpCode::lwarx,
4706
PPCOpProp_LoadReserveExclusiveAccess, node, monitorReg, TR::MemoryReference::createWithIndexReg(cg, objReg, tempReg, lockSize));
4707
generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, cndReg, monitorReg, 0);
4708
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, cndReg);
4709
generateMemSrc1Instruction(cg, lockSize == 8 ? TR::InstOpCode::stdcx_r : TR::InstOpCode::stwcx_r,
4710
node, TR::MemoryReference::createWithIndexReg(cg, objReg, tempReg, lockSize), valReg);
4711
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, loopLabel, cndReg);
4712
generateInstruction(cg, TR::InstOpCode::isync, node);
4713
generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);
4714
generateLabelInstruction(cg, TR::InstOpCode::label, node, reserved_checkLabel);
4715
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tempReg, isPrimitive ? LOCK_RES_PRIMITIVE_ENTER_MASK : LOCK_RES_NON_PRIMITIVE_ENTER_MASK);
4716
generateTrg1Src2Instruction(cg, TR::InstOpCode::andc, node, tempReg, monitorReg, tempReg);
4717
if (!isPrimitive)
4718
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, valReg, metaReg, LOCK_RESERVATION_BIT);
4719
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, tempReg, valReg);
4720
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, cndReg);
4721
if (!isPrimitive)
4722
{
4723
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, monitorReg, monitorReg, LOCK_INC_DEC_VALUE);
4724
generateMemSrc1Instruction(cg, lockSize == 8 ? TR::InstOpCode::std : TR::InstOpCode::stw,
4725
node, TR::MemoryReference::createWithDisplacement(cg, objReg, lwOffset & 0x0000FFFF, lockSize), monitorReg);
4726
}
4727
4728
doneLabel->setEndInternalControlFlow();
4729
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);
4730
4731
TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::call, NULL, callLabel, doneOOLLabel, cg);
4732
cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);
4733
4734
generateLabelInstruction(cg, TR::InstOpCode::label, node, doneOOLLabel);
4735
4736
conditions->stopUsingDepRegs(cg, objReg);
4737
cg->decReferenceCount(node->getFirstChild());
4738
return NULL;
4739
}
4740
4741
static TR::Register *
4742
reservationLockExit(TR::Node *node, int32_t lwOffset, TR::CodeGenerator *cg, TR::RegisterDependencyConditions *conditions, TR::Register *objReg, TR::Register *monitorReg, TR::Register *valReg, TR::Register *tempReg, TR::Register *cndReg, TR::LabelSymbol *callLabel)
4743
{
4744
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
4745
TR::LabelSymbol *resLabel, *doneLabel, *doneOOLLabel;
4746
int32_t lockSize;
4747
TR::Compilation *comp = cg->comp();
4748
4749
TR::Register *metaReg = cg->getMethodMetaDataRegister();
4750
4751
resLabel = generateLabelSymbol(cg);
4752
doneLabel = generateLabelSymbol(cg);
4753
doneOOLLabel = generateLabelSymbol(cg);
4754
4755
bool isPrimitive = node->isPrimitiveLockedRegion();
4756
lockSize = comp->target().is64Bit() && !fej9->generateCompressedLockWord() ? 8 : 4;
4757
4758
/*
4759
* PRIMITIVE reservationLock exit sequence Non-PRIMITIVE reservationLock exit sequence
4760
* ld/lwz monitorReg, [objReg, lwOffset] ld/lwz monitorReg, [objReg, lwOffset]
4761
* andi_r tempReg, monitorReg, PRIMITIVE_EXIT_MASK ori tempReg, metaReg, RES+INC <-- Diff
4762
* cmpli cndReg, tempReg, LOCK_RESERVATION_BIT cmpl cndReg, monitorReg, tempReg <-- Diff
4763
* bne resLabel bne resLabel <-- Diff
4764
* addi valReg, metaReg, LOCK_RESERVATION_BIT <-- Diff
4765
* st valReg, [objReg, lwOffset] <-- Diff
4766
* b doneLabel <-- Diff
4767
* resLabel(startOOLLabel):
4768
* li tempReg, RES_OWNING_COMPLEMENT li tempReg, RES_OWNING_COMPLEMENT
4769
* andc tempReg, monitorReg, tempReg andc tempReg, monitorReg, tempReg
4770
* addi valReg, metaReg, RES_BIT addi valReg, metaReg, RES_BIT
4771
* cmpl cndReg, tempReg, valReg cmpl cndReg, tempReg, valReg
4772
* bne callLabel bne callLabel
4773
* andi_r tempReg, monitorReg, RECURSION_MASK andi_r tempReg, monitorReg, NON_PRIMITIVE_EXIT_MASK <-- Diff
4774
* bne doneLabel beq callLabel <-- Diff
4775
* addi monitorReg, monitorReg, INC addi monitorReg, monitorReg, -INC <-- Diff
4776
* st monitorReg, [objReg, lwOffset] st monitorReg, [objReg, lwOffset]
4777
* b doneLabel <-- Diff
4778
* doneLabel:
4779
* doneOOLLabel:
4780
* === OUT OF LINE ===
4781
* callLabel:
4782
* bl jitMonitorExit
4783
* b doneOOLLabel
4784
*/
4785
4786
generateTrg1MemInstruction(cg, lockSize == 8 ? TR::InstOpCode::ld : TR::InstOpCode::lwz, node, monitorReg, TR::MemoryReference::createWithDisplacement(cg, objReg, lwOffset, lockSize));
4787
if (!node->isPrimitiveLockedRegion())
4788
{
4789
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, tempReg, metaReg, LOCK_RESERVATION_BIT + LOCK_INC_DEC_VALUE);
4790
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, monitorReg, tempReg);
4791
}
4792
else
4793
{
4794
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, tempReg, monitorReg, LOCK_RES_PRIMITIVE_EXIT_MASK);
4795
generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, cndReg, tempReg, LOCK_RESERVATION_BIT);
4796
}
4797
4798
if (!isPrimitive)
4799
{
4800
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, resLabel, cndReg);
4801
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, valReg, metaReg, LOCK_RESERVATION_BIT);
4802
generateMemSrc1Instruction(cg, lockSize == 8 ? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, objReg, lwOffset, lockSize), valReg);
4803
generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);
4804
}
4805
else
4806
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, resLabel, cndReg);
4807
4808
generateLabelInstruction(cg, TR::InstOpCode::label, node, resLabel);
4809
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tempReg, LOCK_RES_OWNING_COMPLEMENT);
4810
generateTrg1Src2Instruction(cg, TR::InstOpCode::andc, node, tempReg, monitorReg, tempReg);
4811
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, valReg, metaReg, LOCK_RESERVATION_BIT);
4812
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, tempReg, valReg);
4813
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, cndReg);
4814
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, tempReg, monitorReg, isPrimitive ? OBJECT_HEADER_LOCK_RECURSION_MASK : LOCK_RES_NON_PRIMITIVE_EXIT_MASK);
4815
if (isPrimitive)
4816
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, doneLabel, cndReg);
4817
else
4818
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, callLabel, cndReg);
4819
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, monitorReg, monitorReg, isPrimitive ? LOCK_INC_DEC_VALUE : -LOCK_INC_DEC_VALUE);
4820
generateMemSrc1Instruction(cg, lockSize == 8 ? TR::InstOpCode::std : TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, objReg, lwOffset, lockSize), monitorReg);
4821
if (!isPrimitive)
4822
generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);
4823
4824
doneLabel->setEndInternalControlFlow();
4825
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);
4826
4827
TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::call, NULL, callLabel, doneOOLLabel, cg);
4828
cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);
4829
4830
generateLabelInstruction(cg, TR::InstOpCode::label, node, doneOOLLabel);
4831
4832
conditions->stopUsingDepRegs(cg, objReg);
4833
cg->decReferenceCount(node->getFirstChild());
4834
return NULL;
4835
}
4836
4837
TR::Register *J9::Power::TreeEvaluator::VMmonexitEvaluator(TR::Node *node, TR::CodeGenerator *cg)
4838
{
4839
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
4840
int32_t lwOffset = fej9->getByteOffsetToLockword((TR_OpaqueClassBlock *) cg->getMonClass(node));
4841
TR::Compilation *comp = cg->comp();
4842
TR_YesNoMaybe isMonitorValueBasedOrValueType = cg->isMonitorValueBasedOrValueType(node);
4843
4844
if (comp->getOption(TR_FullSpeedDebug) ||
4845
(isMonitorValueBasedOrValueType == TR_yes) ||
4846
comp->getOption(TR_DisableInlineMonExit))
4847
{
4848
TR::ILOpCodes opCode = node->getOpCodeValue();
4849
TR::Node::recreate(node, TR::call);
4850
TR::Register *targetRegister = directCallEvaluator(node, cg);
4851
TR::Node::recreate(node, opCode);
4852
return targetRegister;
4853
}
4854
4855
int32_t numDeps = 6;
4856
4857
TR::Node *objNode = node->getFirstChild();
4858
TR::Register *objReg = cg->evaluate(objNode);
4859
4860
TR::Register *monitorReg = cg->allocateRegister();
4861
TR::Register *tempReg = cg->allocateRegister();
4862
TR::Register *threadReg = cg->allocateRegister();
4863
4864
TR::Register *objectClassReg = cg->allocateRegister();
4865
TR::Register *lookupOffsetReg = NULL;
4866
4867
TR::Register *condReg = cg->allocateRegister(TR_CCR);
4868
TR::Register *metaReg = cg->getMethodMetaDataRegister();
4869
4870
TR::Register *baseReg = objReg;
4871
4872
if (lwOffset <= 0)
4873
{
4874
if (comp->getOption(TR_EnableMonitorCacheLookup))
4875
{
4876
lookupOffsetReg = cg->allocateRegister();
4877
numDeps++;
4878
}
4879
}
4880
4881
TR::RegisterDependencyConditions *conditions;
4882
conditions = createConditionsAndPopulateVSXDeps(cg, numDeps);
4883
4884
TR::addDependency(conditions, objReg, TR::RealRegister::NoReg, TR_GPR, cg);
4885
conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();
4886
conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();
4887
4888
TR::addDependency(conditions, monitorReg, TR::RealRegister::NoReg, TR_GPR, cg);
4889
conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();
4890
conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();
4891
4892
TR::addDependency(conditions, tempReg, TR::RealRegister::NoReg, TR_GPR, cg);
4893
4894
TR::addDependency(conditions, threadReg, TR::RealRegister::NoReg, TR_GPR, cg);
4895
4896
TR::addDependency(conditions, objectClassReg, TR::RealRegister::NoReg, TR_GPR, cg);
4897
conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();
4898
conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();
4899
4900
if (lookupOffsetReg)
4901
{
4902
TR::addDependency(conditions, lookupOffsetReg, TR::RealRegister::NoReg, TR_GPR, cg);
4903
conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();
4904
conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();
4905
}
4906
4907
TR::addDependency(conditions, condReg, TR::RealRegister::cr0, TR_CCR, cg);
4908
4909
TR::LabelSymbol *callLabel = generateLabelSymbol(cg);
4910
TR::LabelSymbol *monitorLookupCacheLabel = generateLabelSymbol(cg);
4911
TR::LabelSymbol *fallThruFromMonitorLookupCacheLabel = generateLabelSymbol(cg);
4912
TR::LabelSymbol *startLabel = generateLabelSymbol(cg);
4913
4914
generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel, NULL);
4915
startLabel->setStartInternalControlFlow();
4916
4917
//If object is not known to be value type or value based class at compile time, check at run time
4918
if (isMonitorValueBasedOrValueType == TR_maybe)
4919
{
4920
generateCheckForValueMonitorEnterOrExit(node, callLabel, objReg, objectClassReg, tempReg, threadReg, condReg, cg, J9_CLASS_DISALLOWS_LOCKING_FLAGS);
4921
}
4922
4923
bool simpleLocking = false;
4924
4925
if (lwOffset <= 0)
4926
{
4927
generateLoadJ9Class(node, objectClassReg, objReg, cg);
4928
4929
int32_t offsetOfLockOffset = offsetof(J9Class, lockOffset);
4930
TR::MemoryReference *tempMR = TR::MemoryReference::createWithDisplacement(cg, objectClassReg, offsetOfLockOffset, TR::Compiler->om.sizeofReferenceAddress());
4931
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, objectClassReg, tempMR);
4932
4933
generateTrg1Src1ImmInstruction(cg, comp->target().is64Bit() ? TR::InstOpCode::cmpi8 : TR::InstOpCode::cmpi4, node, condReg, objectClassReg, 0);
4934
4935
if (comp->getOption(TR_EnableMonitorCacheLookup))
4936
{
4937
lwOffset = 0;
4938
generateConditionalBranchInstruction(cg, TR::InstOpCode::ble, node, monitorLookupCacheLabel, condReg);
4939
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, objectClassReg, objReg, objectClassReg);
4940
generateLabelInstruction(cg, TR::InstOpCode::b, node, fallThruFromMonitorLookupCacheLabel);
4941
4942
generateLabelInstruction(cg, TR::InstOpCode::label, node, monitorLookupCacheLabel);
4943
4944
int32_t offsetOfMonitorLookupCache = offsetof(J9VMThread, objectMonitorLookupCache);
4945
4946
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, lookupOffsetReg, objReg);
4947
4948
int32_t t = trailingZeroes(TR::Compiler->om.getObjectAlignmentInBytes());
4949
4950
if (comp->target().is64Bit())
4951
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::sradi, node, lookupOffsetReg, lookupOffsetReg, t);
4952
else
4953
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::srawi, node, lookupOffsetReg, lookupOffsetReg, t);
4954
4955
J9JavaVM * jvm = fej9->getJ9JITConfig()->javaVM;
4956
4957
if (comp->target().is64Bit())
4958
simplifyANDRegImm(node, lookupOffsetReg, lookupOffsetReg, (int64_t) J9VMTHREAD_OBJECT_MONITOR_CACHE_SIZE - 1, cg, objNode);
4959
else
4960
simplifyANDRegImm(node, lookupOffsetReg, lookupOffsetReg, J9VMTHREAD_OBJECT_MONITOR_CACHE_SIZE - 1, cg, objNode);
4961
4962
if (comp->target().is64Bit())
4963
generateShiftLeftImmediateLong(cg, node, lookupOffsetReg, lookupOffsetReg, trailingZeroes((int32_t) TR::Compiler->om.sizeofReferenceField()));
4964
else
4965
generateShiftLeftImmediate(cg, node, lookupOffsetReg, lookupOffsetReg, trailingZeroes((int32_t) TR::Compiler->om.sizeofReferenceField()));
4966
4967
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, lookupOffsetReg, lookupOffsetReg, offsetOfMonitorLookupCache);
4968
4969
generateTrg1MemInstruction(cg, (comp->target().is64Bit() && fej9->generateCompressedLockWord()) ? TR::InstOpCode::lwz :TR::InstOpCode::Op_load, node, objectClassReg,
4970
TR::MemoryReference::createWithIndexReg(cg, metaReg, lookupOffsetReg, TR::Compiler->om.sizeofReferenceField()));
4971
4972
generateTrg1Src1ImmInstruction(cg, comp->target().is64Bit() ? TR::InstOpCode::cmpi8 : TR::InstOpCode::cmpi4, node, condReg, objectClassReg, 0);
4973
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, callLabel, condReg);
4974
4975
int32_t offsetOfMonitor = offsetof(J9ObjectMonitor, monitor);
4976
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, lookupOffsetReg,
4977
TR::MemoryReference::createWithDisplacement(cg, objectClassReg, offsetOfMonitor, TR::Compiler->om.sizeofReferenceAddress()));
4978
4979
int32_t offsetOfUserData = offsetof(J9ThreadAbstractMonitor, userData);
4980
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, lookupOffsetReg,
4981
TR::MemoryReference::createWithDisplacement(cg, lookupOffsetReg, offsetOfUserData, TR::Compiler->om.sizeofReferenceAddress()));
4982
4983
generateTrg1Src2Instruction(cg, comp->target().is64Bit() ? TR::InstOpCode::cmp8 : TR::InstOpCode::cmp4, node, condReg, lookupOffsetReg, objReg);
4984
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, condReg);
4985
4986
int32_t offsetOfAlternateLockWord = offsetof(J9ObjectMonitor, alternateLockword);
4987
4988
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, objectClassReg, objectClassReg, offsetOfAlternateLockWord);
4989
4990
generateLabelInstruction(cg, TR::InstOpCode::label, node, fallThruFromMonitorLookupCacheLabel);
4991
}
4992
else
4993
{
4994
generateConditionalBranchInstruction(cg, TR::InstOpCode::ble, node, callLabel, condReg);
4995
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, objectClassReg, objReg, objectClassReg);
4996
}
4997
4998
simpleLocking = true;
4999
lwOffset = 0;
5000
baseReg = objectClassReg;
5001
}
5002
5003
/* If the -XX:-GlobalLockReservation option is set, try to use the original aggressive reserved locking code path. */
5004
if (!fej9->isEnableGlobalLockReservationSet())
5005
{
5006
bool reserveLocking = false, normalLockWithReservationPreserving = false;
5007
5008
if (!simpleLocking && comp->getOption(TR_ReservingLocks))
5009
TR::TreeEvaluator::evaluateLockForReservation(node, &reserveLocking, &normalLockWithReservationPreserving, cg);
5010
5011
if (reserveLocking)
5012
return reservationLockExit(node, lwOffset, cg, conditions, baseReg, monitorReg, threadReg, tempReg, condReg, callLabel);
5013
}
5014
5015
int32_t lockSize;
5016
TR::InstOpCode::Mnemonic loadOpCode, storeOpCode, reservedLoadOpCode, conditionalStoreOpCode, compareLogicalOpCode, compareLogicalImmOpCode;
5017
5018
if (comp->target().is64Bit() && !fej9->generateCompressedLockWord())
5019
{
5020
lockSize = 8;
5021
loadOpCode = TR::InstOpCode::ld;
5022
storeOpCode = TR::InstOpCode::std;
5023
reservedLoadOpCode = TR::InstOpCode::ldarx;
5024
conditionalStoreOpCode = TR::InstOpCode::stdcx_r;
5025
compareLogicalOpCode = TR::InstOpCode::cmpl8;
5026
compareLogicalImmOpCode = TR::InstOpCode::cmpli8;
5027
}
5028
else
5029
{
5030
lockSize = 4;
5031
loadOpCode = TR::InstOpCode::lwz;
5032
storeOpCode = TR::InstOpCode::stw;
5033
reservedLoadOpCode = TR::InstOpCode::lwarx;
5034
conditionalStoreOpCode = TR::InstOpCode::stwcx_r;
5035
compareLogicalOpCode = TR::InstOpCode::cmpl4;
5036
compareLogicalImmOpCode = TR::InstOpCode::cmpli4;
5037
}
5038
5039
/*
5040
* Read only locks do not support either the Reserved bit nor the Learning bit.
5041
* They are disabled until the code path is updated.
5042
*/
5043
if (true || !ppcSupportsReadMonitors || !node->isReadMonitor())
5044
{
5045
/*
5046
* JIT unlocking fast path checks:
5047
* 1. Check if lockword matches TID and the lower 8 bits are clear. If so, clear lockword to unlock the object.
5048
* 2. Check if TID matches, Learning bit is clear, and Inflated bit is clear. If not, call VM.
5049
* 3. Check if RC field is at least 1. If so, decrement RC.
5050
* 4. All fast path checks failed so go to VM.
5051
*
5052
* Check 1 catches Flat-Locked (non-nested, FLC bit clear).
5053
* Check 2 catches New-PreLearning, New-AutoReserve, Learning-Unlocked, Learning-Locked, Flat-Unlocked and Inflated and sends them to the VM.
5054
* Check 3 catches Flat-Locked (nested case) and Reserved-Locked.
5055
* Check 4 catches Reserved-Unlocked and Flat-Locked (non-nested case, FLC bit set) and sends it to the VM.
5056
*
5057
*
5058
* ld/lwz monitorReg, lwOffset(baseReg)
5059
* li tempReg, 0
5060
* cmpl cr0, monitorReg, metaReg
5061
* bne decrementCheckLabel
5062
* lwsync
5063
* st tempReg, lwOffset(baseReg)
5064
* b doneLabel
5065
*
5066
* decrementCheckLabel:
5067
* li tempReg, LOCK_NON_PRIMITIVE_EXIT_IGNORE_MASK
5068
* andc tempReg, monitorReg, tempReg
5069
* cmpl cr0, tempReg, metaReg
5070
* bne callLabel
5071
* andi. tempReg, monitorReg, OBJECT_HEADER_LOCK_RECURSION_MASK
5072
* beq callLabel
5073
* addi monitorReg, monitorReg, -LOCK_INC_DEC_VALUE
5074
* st monitorReg, lwOffset(baseReg)
5075
*
5076
* doneLabel:
5077
* callReturnLabel:
5078
* === OUT OF LINE ===
5079
* callLabel:
5080
* bl jitMonitorExit
5081
* b callReturnLabel
5082
*/
5083
5084
TR::LabelSymbol *decrementCheckLabel, *doneLabel;
5085
5086
decrementCheckLabel = generateLabelSymbol(cg);
5087
doneLabel = generateLabelSymbol(cg);
5088
5089
generateTrg1MemInstruction(cg, loadOpCode, node, monitorReg, TR::MemoryReference::createWithDisplacement(cg, baseReg, lwOffset, lockSize));
5090
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tempReg, 0);
5091
generateTrg1Src2Instruction(cg, compareLogicalOpCode, node, condReg, monitorReg, metaReg);
5092
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, decrementCheckLabel, condReg);
5093
5094
// exiting from read monitors still needs lwsync
5095
// (ensures loads have completed before releasing lock)
5096
if (comp->target().isSMP())
5097
generateInstruction(cg, TR::InstOpCode::lwsync, node);
5098
5099
generateMemSrc1Instruction(cg, storeOpCode, node, TR::MemoryReference::createWithDisplacement(cg, baseReg, lwOffset, lockSize), tempReg);
5100
generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);
5101
5102
generateLabelInstruction(cg, TR::InstOpCode::label, node, decrementCheckLabel);
5103
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tempReg, LOCK_NON_PRIMITIVE_EXIT_IGNORE_MASK);
5104
generateTrg1Src2Instruction(cg, TR::InstOpCode::andc, node, tempReg, monitorReg, tempReg);
5105
generateTrg1Src2Instruction(cg, compareLogicalOpCode, node, condReg, tempReg, metaReg);
5106
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, condReg);
5107
5108
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, tempReg, monitorReg, OBJECT_HEADER_LOCK_RECURSION_MASK);
5109
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, callLabel, condReg);
5110
5111
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, monitorReg, monitorReg, -LOCK_INC_DEC_VALUE);
5112
generateMemSrc1Instruction(cg, storeOpCode, node, TR::MemoryReference::createWithDisplacement(cg, baseReg, lwOffset, lockSize), monitorReg);
5113
5114
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);
5115
5116
doneLabel->setEndInternalControlFlow();
5117
5118
TR::LabelSymbol *callReturnLabel = generateLabelSymbol(cg);
5119
5120
TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::call, NULL, callLabel, callReturnLabel, cg);
5121
cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);
5122
5123
generateLabelInstruction(cg, TR::InstOpCode::label, node, callReturnLabel);
5124
5125
conditions->stopUsingDepRegs(cg, objReg);
5126
cg->decReferenceCount(objNode);
5127
}
5128
else
5129
{
5130
// read-only locks, ReaderReg = 0x0000 0000
5131
// li tempReg, offset
5132
// lwsync
5133
// loopLabel:
5134
// lwarx monitorReg, [baseReg, tempReg]
5135
// cmpi condReg, monitorReg, 0x6 // count == 1 (flc bit is set)
5136
// addi threadReg, monitorReg, -4
5137
// beq decLabel
5138
// stwcx [baseReg, tempReg], threadReg
5139
// bne loopLabel
5140
// b doneLabel
5141
// decLabel: (a misleading name, really a RestoreAndCallLabel)
5142
// andi_r threadReg, monitorReg, 0x3
5143
// or threadReg, threadReg, metaReg
5144
// stwcx [baseReg, tempReg], threadReg
5145
// beq callLabel
5146
// b loopLabel
5147
// doneLabel:
5148
// callReturnLabel:
5149
// === OUT OF LINE ===
5150
// callLabel:
5151
// bl jitMonitorExit
5152
// b callReturnLabel;
5153
5154
TR::LabelSymbol *loopLabel, *decLabel, *doneLabel;
5155
loopLabel = generateLabelSymbol(cg);
5156
decLabel = generateLabelSymbol(cg);
5157
doneLabel = generateLabelSymbol(cg);
5158
5159
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tempReg, lwOffset);
5160
5161
// exiting from read monitors still needs lwsync
5162
// (ensures loads have completed before releasing lock)
5163
if (comp->target().isSMP())
5164
generateInstruction(cg, TR::InstOpCode::lwsync, node);
5165
5166
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel, conditions);
5167
generateTrg1MemInstruction(cg, reservedLoadOpCode, node, monitorReg, TR::MemoryReference::createWithIndexReg(cg, baseReg, tempReg, lockSize));
5168
5169
generateTrg1Src1ImmInstruction(cg, compareLogicalImmOpCode, node, condReg, monitorReg, 0x6);
5170
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, threadReg, monitorReg, -4);
5171
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, decLabel, condReg);
5172
5173
generateMemSrc1Instruction(cg, conditionalStoreOpCode, node, TR::MemoryReference::createWithIndexReg(cg, baseReg, tempReg, lockSize), threadReg);
5174
5175
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, loopLabel, condReg);
5176
generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);
5177
5178
generateLabelInstruction(cg, TR::InstOpCode::label, node, decLabel);
5179
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, threadReg, monitorReg, condReg, 0x3);
5180
generateTrg1Src2Instruction(cg, TR::InstOpCode::OR, node, threadReg, threadReg, metaReg);
5181
generateMemSrc1Instruction(cg, conditionalStoreOpCode, node, TR::MemoryReference::createWithIndexReg(cg, baseReg, tempReg, lockSize), threadReg);
5182
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, callLabel, condReg);
5183
generateLabelInstruction(cg, TR::InstOpCode::b, node, loopLabel);
5184
5185
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);
5186
5187
doneLabel->setEndInternalControlFlow();
5188
5189
TR::LabelSymbol *callReturnLabel = generateLabelSymbol(cg);
5190
5191
TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::call, NULL, callLabel, callReturnLabel, cg);
5192
cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);
5193
5194
generateLabelInstruction(cg, TR::InstOpCode::label, node, callReturnLabel);
5195
5196
conditions->stopUsingDepRegs(cg, objReg);
5197
cg->decReferenceCount(objNode);
5198
}
5199
5200
return (NULL);
5201
}
5202
5203
static void genInitObjectHeader(TR::Node *node, TR::Instruction *&iCursor, TR_OpaqueClassBlock *clazz, TR::Register *classReg, TR::Register *resReg, TR::Register *zeroReg,
5204
TR::Register *condReg, TR::Register *temp1Reg, TR::Register *temp2Reg, TR::Register * packedClobberedOffset, TR::RegisterDependencyConditions *conditions, bool needZeroInit,
5205
TR::CodeGenerator *cg);
5206
5207
static void genHeapAlloc(TR::Node *node, TR::Instruction *&iCursor, TR_OpaqueClassBlock *clazz, bool isVariableLen, TR::Register *enumReg, TR::Register *classReg, TR::Register *resReg, TR::Register *zeroReg, TR::Register *condReg,
5208
TR::Register *dataSizeReg, TR::Register *heapTopReg, TR::Register *sizeReg, TR::Register *temp1Reg, TR::Register *temp2Reg, TR::Register *temp3Reg, TR::LabelSymbol *callLabel, TR::LabelSymbol *doneLabel,
5209
int32_t allocSize, int32_t elementSize, bool usingTLH, bool needZeroInit, TR::RegisterDependencyConditions *dependencies, TR::CodeGenerator *cg)
5210
{
5211
TR::Compilation *comp = cg->comp();
5212
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
5213
TR::Register *metaReg = cg->getMethodMetaDataRegister();
5214
TR::ILOpCodes opCode = node->getOpCodeValue();
5215
5216
if (comp->getOptions()->realTimeGC())
5217
{
5218
#if defined(J9VM_GC_REALTIME)
5219
// Use temp3Reg to hold the javaVM.
5220
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp3Reg,
5221
TR::MemoryReference::createWithDisplacement(cg, metaReg, fej9->thisThreadJavaVMOffset(), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5222
5223
// Realtime size classes are now a pointer in J9JavaVM rather than an inlined struct of arrays, so we can't use J9JavaVM as a base pointer anymore
5224
// Use temp3Reg to hold J9JavaVM->realTimeSizeClasses
5225
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp3Reg,
5226
TR::MemoryReference::createWithDisplacement(cg, temp3Reg, fej9->getRealtimeSizeClassesOffset(), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5227
5228
// heap allocation, so proceed
5229
if (isVariableLen)
5230
{
5231
// make sure size isn't too big
5232
// convert max object size to num elements because computing an object size from num elements may overflow
5233
5234
uintptr_t maxSize = fej9->getMaxObjectSizeForSizeClass();
5235
TR_ASSERT(((int32_t)(maxSize)-allocSize)/elementSize <= USHRT_MAX, "MaxObjectSizeForSizeClass won't fit into 16-bits.");
5236
5237
iCursor = generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, condReg, enumReg, ((int32_t)(maxSize)-allocSize)/elementSize, iCursor);
5238
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, callLabel, condReg, iCursor);
5239
5240
if (TR::Compiler->om.useHybridArraylets())
5241
{
5242
// Zero length arrays are discontiguous (i.e. they also need the discontiguous length field to be 0) because
5243
// they are indistinguishable from non-zero length discontiguous arrays
5244
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, condReg, enumReg, 0, iCursor);
5245
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, callLabel, condReg, iCursor);
5246
}
5247
5248
// now compute size of object in bytes
5249
TR_ASSERT(elementSize == 1 || elementSize == 2 || elementSize == 4 || elementSize == 8 || elementSize == 16, "Illegal element size for genHeapAlloc()");
5250
5251
TR::Register *scaledSizeReg = enumReg;
5252
5253
if (elementSize > 1)
5254
{
5255
iCursor = generateShiftLeftImmediate(cg, node, dataSizeReg, enumReg, trailingZeroes(elementSize), iCursor);
5256
scaledSizeReg = dataSizeReg;
5257
}
5258
5259
// need to round up to sizeof(UDATA) so we can use it to index into size class index array
5260
// conservatively just add sizeof(UDATA) bytes and round
5261
if (elementSize < sizeof(UDATA))
5262
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, dataSizeReg, scaledSizeReg, allocSize + sizeof(UDATA) - 1, iCursor);
5263
else
5264
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, dataSizeReg, scaledSizeReg, allocSize, iCursor);
5265
5266
if (elementSize < sizeof(UDATA))
5267
{
5268
if (comp->target().is64Bit())
5269
iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicr, node, dataSizeReg, dataSizeReg, 0, int64_t(-sizeof(UDATA)), iCursor);
5270
else
5271
iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, dataSizeReg, dataSizeReg, 0, -sizeof(UDATA), iCursor);
5272
}
5273
5274
#ifdef J9VM_INTERP_FLAGS_IN_CLASS_SLOT
5275
iCursor = generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, condReg, dataSizeReg, J9_GC_MINIMUM_OBJECT_SIZE, iCursor);
5276
TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);
5277
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, PPCOpProp_BranchLikely, node, doneLabel, condReg, iCursor);
5278
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, dataSizeReg, J9_GC_MINIMUM_OBJECT_SIZE, iCursor);
5279
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, iCursor);
5280
#endif
5281
5282
// J9JavaVM (or realTimeSizeClasses when J9_CHANGES_PR95193 is defined) + rounded data size + SizeClassesIndexOffset is pointer to the size class
5283
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp1Reg, dataSizeReg, temp3Reg, iCursor);
5284
5285
//Now adjust dataSizeReg to only include the size of the array data in bytes, since this will be used in genInitArrayHeader();
5286
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, dataSizeReg, dataSizeReg, -allocSize, iCursor);
5287
iCursor = generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, heapTopReg,
5288
TR::MemoryReference::createWithDisplacement(cg, temp1Reg, fej9->getSizeClassesIndexOffset(), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5289
// heapTopReg now holds size class
5290
5291
// get next cell for this size class at vmThread + thisThreadAllocationCacheCurrentOffset(0) + (size class)*sizeof(J9VMGCSegregatedAllocationCacheEntry)
5292
TR_ASSERT(sizeof(J9VMGCSegregatedAllocationCacheEntry) == sizeof(UDATA*) * 2,
5293
"J9VMGCSegregatedAllocationCacheEntry may need to be padded to avoid multiply in array access.");
5294
5295
if (comp->target().is64Bit())
5296
iCursor = generateShiftLeftImmediateLong(cg, node, temp1Reg, heapTopReg, trailingZeroes((int32_t)sizeof(J9VMGCSegregatedAllocationCacheEntry)), iCursor);
5297
else
5298
iCursor = generateShiftLeftImmediate(cg, node, temp1Reg, heapTopReg, trailingZeroes((int32_t)sizeof(J9VMGCSegregatedAllocationCacheEntry)), iCursor);
5299
5300
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, sizeReg, temp1Reg, metaReg, iCursor);
5301
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, resReg,
5302
TR::MemoryReference::createWithDisplacement(cg, sizeReg, fej9->thisThreadAllocationCacheCurrentOffset(0), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5303
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,
5304
TR::MemoryReference::createWithDisplacement(cg, sizeReg, fej9->thisThreadAllocationCacheTopOffset(0), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5305
5306
// if we've reached the top, then no cell available, use slow path
5307
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, resReg, temp1Reg, iCursor);
5308
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, callLabel, condReg, iCursor);
5309
5310
// have a valid cell, need to update current cell pointer
5311
if (comp->target().is64Bit())
5312
iCursor = generateShiftLeftImmediateLong(cg, node, temp1Reg, heapTopReg, trailingZeroes((int32_t)sizeof(UDATA)), iCursor);
5313
else
5314
iCursor = generateShiftLeftImmediate(cg, node, temp1Reg, heapTopReg, trailingZeroes((int32_t)sizeof(UDATA)), iCursor);
5315
5316
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp1Reg, temp1Reg, temp3Reg, iCursor);
5317
5318
iCursor = generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, temp1Reg,
5319
TR::MemoryReference::createWithDisplacement(cg, temp1Reg, fej9->getSmallCellSizesOffset(), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5320
5321
// temp1Reg now holds cell size
5322
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp1Reg, temp1Reg, resReg, iCursor);
5323
5324
//temp1Reg now holds new current cell pointer. Update it in memory:
5325
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,
5326
TR::MemoryReference::createWithDisplacement(cg, sizeReg, fej9->thisThreadAllocationCacheCurrentOffset(0), TR::Compiler->om.sizeofReferenceAddress()), temp1Reg, iCursor);
5327
}
5328
else
5329
{
5330
// sizeClass will be bogus for variable length allocations because it only includes the header size (+ arraylet ptr for arrays)
5331
UDATA sizeClass = fej9->getObjectSizeClass(allocSize);
5332
5333
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, resReg, TR::MemoryReference::createWithDisplacement(cg, metaReg,
5334
fej9->thisThreadAllocationCacheCurrentOffset(sizeClass), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5335
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp2Reg, TR::MemoryReference::createWithDisplacement(cg, metaReg,
5336
fej9->thisThreadAllocationCacheTopOffset(sizeClass), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5337
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, resReg, temp2Reg, iCursor);
5338
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, callLabel, condReg, iCursor);
5339
5340
//now bump the current updatepointer
5341
if (fej9->getCellSizeForSizeClass(sizeClass) <= UPPER_IMMED)
5342
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, temp1Reg, resReg, fej9->getCellSizeForSizeClass(sizeClass), iCursor);
5343
else
5344
{
5345
iCursor = loadConstant(cg, node, (int32_t)fej9->getCellSizeForSizeClass(sizeClass), temp1Reg, iCursor);
5346
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp1Reg, temp1Reg, resReg, iCursor);
5347
}
5348
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,
5349
TR::MemoryReference::createWithDisplacement(cg, metaReg, fej9->thisThreadAllocationCacheCurrentOffset(sizeClass), TR::Compiler->om.sizeofReferenceAddress()), temp1Reg, iCursor);
5350
}
5351
5352
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, zeroReg, 0, iCursor);
5353
5354
//we're done
5355
return;
5356
#endif
5357
} // if (comp->getOptions()->realTimeGC())
5358
else
5359
{
5360
uint32_t maxSafeSize = cg->getMaxObjectSizeGuaranteedNotToOverflow();
5361
5362
bool generateArraylets = comp->generateArraylets();
5363
bool isArrayAlloc = (opCode == TR::newarray || opCode == TR::anewarray);
5364
5365
if (isArrayAlloc)
5366
{
5367
if (TR::Compiler->om.useHybridArraylets())
5368
{
5369
int32_t maxContiguousArraySize = TR::Compiler->om.maxContiguousArraySizeInBytes() / elementSize;
5370
TR_ASSERT(maxContiguousArraySize >= 0, "Unexpected negative size for max contiguous array size");
5371
if (maxContiguousArraySize > UPPER_IMMED)
5372
{
5373
iCursor = loadConstant(cg, node, maxContiguousArraySize, temp2Reg, iCursor);
5374
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::cmpl4, node, condReg, enumReg, temp2Reg, iCursor);
5375
}
5376
else
5377
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, condReg, enumReg, maxContiguousArraySize, iCursor);
5378
5379
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, callLabel, condReg, iCursor);
5380
}
5381
5382
if (isVariableLen)
5383
{ // Inline runtime zero length non-packed array allocation
5384
// Zero length arrays are discontiguous (i.e. they also need the discontiguous length field to be 0) because
5385
// they are indistinguishable from non-zero length discontiguous arrays
5386
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpli4, node, condReg, enumReg, 0, iCursor);
5387
TR::LabelSymbol *nonZeroLengthLabel = generateLabelSymbol(cg);
5388
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, nonZeroLengthLabel, condReg, iCursor);
5389
5390
int32_t zeroLenArraySize = (TR::Compiler->om.discontiguousArrayHeaderSizeInBytes() + TR::Compiler->om.getObjectAlignmentInBytes() - 1) & (-TR::Compiler->om.getObjectAlignmentInBytes());
5391
TR_ASSERT(zeroLenArraySize >= J9_GC_MINIMUM_OBJECT_SIZE, "Zero-length array size must be bigger than MIN_OBJECT_SIZE");
5392
TR_ASSERT(zeroLenArraySize <= maxSafeSize, "Zero-length array size must be smaller than maxSafeSize");
5393
// Load TLH heapAlloc and heapTop values.
5394
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, resReg,
5395
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapAlloc), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5396
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, heapTopReg,
5397
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapTop), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5398
5399
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, temp2Reg, resReg, zeroLenArraySize, iCursor);
5400
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp2Reg, heapTopReg, iCursor);
5401
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, callLabel, condReg, iCursor);
5402
5403
if (comp->compileRelocatableCode())
5404
genInitObjectHeader(node, iCursor, clazz, classReg, resReg, zeroReg, condReg, heapTopReg, sizeReg, NULL, dependencies, needZeroInit, cg);
5405
else
5406
genInitObjectHeader(node, iCursor, clazz, NULL, resReg, zeroReg, condReg, heapTopReg, sizeReg, NULL, dependencies, needZeroInit, cg);
5407
5408
UDATA offsetSizeFields = fej9->getOffsetOfDiscontiguousArraySizeField();
5409
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node,
5410
TR::MemoryReference::createWithDisplacement(cg, resReg, offsetSizeFields-4, 4), enumReg, iCursor);
5411
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node,
5412
TR::MemoryReference::createWithDisplacement(cg, resReg, offsetSizeFields, 4), enumReg, iCursor);
5413
5414
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,
5415
TR::MemoryReference::createWithDisplacement(cg, metaReg,
5416
offsetof(J9VMThread, heapAlloc), TR::Compiler->om.sizeofReferenceAddress()), temp2Reg, iCursor);
5417
iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);
5418
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, nonZeroLengthLabel);
5419
}
5420
}
5421
5422
if (usingTLH)
5423
{
5424
bool sizeInReg = (isVariableLen || (allocSize > UPPER_IMMED));
5425
bool shouldAlignToCacheBoundary = false;
5426
int32_t instanceBoundaryForAlignment = 64;
5427
5428
static bool verboseDualTLH = feGetEnv("TR_verboseDualTLH") != NULL;
5429
5430
if (isVariableLen)
5431
{
5432
// Detect large or negative number of elements in case addr wrap-around
5433
5434
if (maxSafeSize < 0x00100000)
5435
{
5436
// NOTE: TR::InstOpCode::bge and the special shifts are used to cover every
5437
// possible corner cases, with 32byte maximum object header.
5438
iCursor = generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, condReg, enumReg, (maxSafeSize >> 6) << 2, iCursor);
5439
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, callLabel, condReg, iCursor);
5440
}
5441
else
5442
{
5443
uintptr_t mask;
5444
if (comp->target().is64Bit())
5445
{
5446
mask = 0xFFFFFFFF << (27 - leadingZeroes(maxSafeSize));
5447
iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm_r, node, temp2Reg, enumReg, condReg, 0, mask, iCursor);
5448
}
5449
else
5450
{
5451
mask = (0xFFFFFFFF << (11 - leadingZeroes(maxSafeSize))) & 0x0000FFFF;
5452
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andis_r, node, temp2Reg, enumReg, condReg, mask, iCursor);
5453
}
5454
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, condReg, iCursor);
5455
}
5456
}
5457
5458
//TODO: This code is never executed, check if this can be deleted now.
5459
if (!cg->isDualTLH())
5460
{
5461
//All of this code never gets executed because of the 0 && in
5462
//the inside if statement. Candidate for deletion
5463
5464
if (!isVariableLen)
5465
{
5466
static char *disableAlign = feGetEnv("TR_DisableAlignAlloc");
5467
5468
if (0 && !disableAlign && (node->getOpCodeValue() == TR::New) && (comp->getMethodHotness() >= hot || node->shouldAlignTLHAlloc()))
5469
{
5470
TR_OpaqueMethodBlock *ownMethod = node->getOwningMethod();
5471
5472
TR::Node *classChild = node->getFirstChild();
5473
char * className = NULL;
5474
TR_OpaqueClassBlock *clazz = NULL;
5475
5476
if (classChild && classChild->getSymbolReference() && !classChild->getSymbolReference()->isUnresolved())
5477
{
5478
TR::SymbolReference *symRef = classChild->getSymbolReference();
5479
TR::Symbol *sym = symRef->getSymbol();
5480
5481
if (sym && sym->getKind() == TR::Symbol::IsStatic && sym->isClassObject())
5482
{
5483
TR::StaticSymbol * staticSym = symRef->getSymbol()->castToStaticSymbol();
5484
void * staticAddress = staticSym->getStaticAddress();
5485
if (symRef->getCPIndex() >= 0)
5486
{
5487
if (!staticSym->addressIsCPIndexOfStatic() && staticAddress)
5488
{
5489
int32_t len;
5490
className = TR::Compiler->cls.classNameChars(comp, symRef, len);
5491
clazz = (TR_OpaqueClassBlock *) staticAddress;
5492
}
5493
}
5494
}
5495
}
5496
5497
int32_t instanceSizeForAlignment = 56;
5498
static char *alignSize = feGetEnv("TR_AlignInstanceSize");
5499
static char *alignBoundary = feGetEnv("TR_AlignInstanceBoundary");
5500
5501
if (alignSize)
5502
instanceSizeForAlignment = atoi(alignSize);
5503
if (alignBoundary)
5504
instanceBoundaryForAlignment = atoi(alignBoundary);
5505
5506
if (clazz && !cg->getCurrentEvaluationBlock()->isCold() && TR::Compiler->cls.classInstanceSize(clazz) >= instanceSizeForAlignment)
5507
{
5508
shouldAlignToCacheBoundary = true;
5509
5510
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,
5511
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapAlloc), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5512
5513
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, resReg, temp1Reg, instanceBoundaryForAlignment - 1, iCursor);
5514
if (comp->target().is64Bit())
5515
iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicr, node, resReg, resReg, 0, int64_t(-instanceBoundaryForAlignment), iCursor);
5516
else
5517
iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, resReg, resReg, 0, -instanceBoundaryForAlignment, iCursor);
5518
}
5519
}
5520
}
5521
5522
if (!shouldAlignToCacheBoundary)
5523
{
5524
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, resReg,
5525
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapAlloc), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5526
}
5527
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, heapTopReg,
5528
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapTop), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5529
5530
if (needZeroInit)
5531
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, zeroReg, 0, iCursor);
5532
5533
}
5534
else
5535
{
5536
//DualTLH support, use nonZeroTLH if optimizer says we can.
5537
5538
if (node->canSkipZeroInitialization())
5539
{
5540
5541
if (verboseDualTLH)
5542
fprintf(stderr, "DELETEME genHeapAlloc useNonZeroTLH [%d] isVariableLen [%d] node: [%p] %s [@%s]\n", 1, isVariableLen, node, comp->signature(),
5543
comp->getHotnessName(comp->getMethodHotness()));
5544
5545
//Load non-zeroed TLH heapAlloc and heapTop values.
5546
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, resReg,
5547
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, nonZeroHeapAlloc), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5548
5549
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, heapTopReg,
5550
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, nonZeroHeapTop), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5551
5552
}
5553
else
5554
{
5555
if (verboseDualTLH)
5556
fprintf(stderr, "DELETEME genHeapAlloc useNonZeroTLH [%d] isVariableLen [%d] node: [%p] %s [@%s]\n", 0, isVariableLen, node, comp->signature(),
5557
comp->getHotnessName(comp->getMethodHotness()));
5558
5559
//Load zeroed TLH heapAlloc and heapTop values.
5560
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, resReg,
5561
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapAlloc), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5562
5563
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, heapTopReg,
5564
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapTop), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5565
}
5566
5567
} //if(!cg->isDualTLH()) == false
5568
5569
if (sizeInReg)
5570
{
5571
//Size will put into sizeReg
5572
//Get the size of the object
5573
//See if we can put into a single arraylet, if not call the helper.
5574
//Add enough padding to make it a multiple of OBJECT_ALIGNMENT
5575
if (isVariableLen)
5576
{
5577
int32_t elementSize;
5578
if (comp->useCompressedPointers() && node->getOpCodeValue() == TR::anewarray)
5579
elementSize = TR::Compiler->om.sizeofReferenceField();
5580
else
5581
elementSize = TR::Compiler->om.getSizeOfArrayElement(node);
5582
5583
// Check to see if the size of the array will fit in a single arraylet leaf.
5584
//
5585
if (generateArraylets && (node->getOpCodeValue() == TR::anewarray || node->getOpCodeValue() == TR::newarray))
5586
{
5587
int32_t arrayletLeafSize = TR::Compiler->om.arrayletLeafSize();
5588
int32_t maxContiguousArrayletLeafSizeInBytes = arrayletLeafSize - TR::Compiler->om.sizeofReferenceAddress(); //need to add definition
5589
int32_t maxArrayletSizeInElements = maxContiguousArrayletLeafSizeInBytes / elementSize;
5590
if (maxArrayletSizeInElements <= UPPER_IMMED)
5591
{
5592
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, condReg, enumReg, maxArrayletSizeInElements, iCursor);
5593
}
5594
else
5595
{
5596
iCursor = loadConstant(cg, node, maxArrayletSizeInElements, temp1Reg, iCursor);
5597
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, condReg, enumReg, temp1Reg, iCursor);
5598
}
5599
static const char *p = feGetEnv("TR_TarokPreLeafSizeCheckVarBreak");
5600
if (p)
5601
generateInstruction(cg, TR::InstOpCode::bad, node);
5602
5603
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, callLabel, condReg, iCursor);
5604
}
5605
5606
int32_t round; // zero indicates no rounding is necessary
5607
round = (elementSize >= TR::Compiler->om.getObjectAlignmentInBytes()) ? 0 : TR::Compiler->om.getObjectAlignmentInBytes();
5608
bool headerAligned = allocSize % TR::Compiler->om.getObjectAlignmentInBytes() ? 0 : 1;
5609
5610
//TODO: The code below pads up the object allocation size so that zero init code later
5611
//will have multiples of wordsize to work with. For now leaving this code as is, but
5612
//check if its worthwhile to remove these extra instructions added here for padding as
5613
//zero init will be removed now.
5614
if (elementSize >= 2)
5615
{
5616
if (comp->target().is64Bit())
5617
iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldic, node, dataSizeReg, enumReg, trailingZeroes(elementSize), CONSTANT64(0x00000000FFFFFFFF) << trailingZeroes(elementSize));
5618
else
5619
iCursor = generateShiftLeftImmediate(cg, node, dataSizeReg, enumReg, trailingZeroes(elementSize), iCursor);
5620
5621
}
5622
if (needZeroInit && elementSize <= 2)
5623
{
5624
// the zero initialization code uses a loop of stwu's, and
5625
// so dataSizeReg must be rounded up to a multiple of 4
5626
if (elementSize == 2)
5627
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, dataSizeReg, dataSizeReg, 3, iCursor);
5628
else //elementSize == 1
5629
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, dataSizeReg, enumReg, 3, iCursor);
5630
5631
if (comp->target().is64Bit() && elementSize != 1)
5632
iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicr, node, dataSizeReg, dataSizeReg, 0, int64_t(-4), iCursor);
5633
else
5634
iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, dataSizeReg, dataSizeReg, 0, -4, iCursor);
5635
}
5636
5637
if ((round != 0 && (!needZeroInit || round != 4)) || !headerAligned)
5638
{
5639
// Round the total size to a multiple of OBJECT_ALIGNMENT
5640
if (elementSize == 1 && !needZeroInit)
5641
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, sizeReg, enumReg, allocSize + round - 1, iCursor);
5642
else
5643
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, sizeReg, dataSizeReg, allocSize + round - 1, iCursor);
5644
if (comp->target().is64Bit() && elementSize != 1)
5645
iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicr, node, sizeReg, sizeReg, 0, int64_t(-round), iCursor);
5646
else
5647
iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, sizeReg, sizeReg, 0, -round, iCursor);
5648
}
5649
else
5650
{
5651
if (elementSize == 1 && !needZeroInit)
5652
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, sizeReg, enumReg, allocSize, iCursor);
5653
else
5654
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, sizeReg, dataSizeReg, allocSize, iCursor);
5655
}
5656
5657
#ifdef J9VM_INTERP_FLAGS_IN_CLASS_SLOT
5658
if (!((node->getOpCodeValue() == TR::New) || (node->getOpCodeValue() == TR::anewarray) || (node->getOpCodeValue() == TR::newarray)))
5659
{
5660
iCursor = generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, condReg, sizeReg, J9_GC_MINIMUM_OBJECT_SIZE, iCursor);
5661
TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);
5662
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, PPCOpProp_BranchLikely, node, doneLabel, condReg, iCursor);
5663
5664
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, sizeReg, J9_GC_MINIMUM_OBJECT_SIZE, iCursor);
5665
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, iCursor);
5666
}
5667
#endif
5668
} //if (isVariableLen)
5669
else
5670
{
5671
// Check to see if the size of the array will fit in a single arraylet leaf.
5672
//
5673
if (generateArraylets && (node->getOpCodeValue() == TR::anewarray || node->getOpCodeValue() == TR::newarray))
5674
{
5675
int32_t arrayletLeafSize = TR::Compiler->om.arrayletLeafSize();
5676
5677
if (allocSize >= arrayletLeafSize + TR::Compiler->om.contiguousArrayHeaderSizeInBytes())
5678
{
5679
static const char *p = feGetEnv("TR_TarokPreLeafSizeCheckConstBreak");
5680
if (p)
5681
generateInstruction(cg, TR::InstOpCode::bad, node);
5682
5683
iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, callLabel, iCursor);
5684
}
5685
}
5686
5687
iCursor = loadConstant(cg, node, allocSize, sizeReg, iCursor);
5688
}
5689
} //if (sizeInReg)
5690
5691
// Calculate the after-allocation heapAlloc: if the size is huge,
5692
// we need to check address wrap-around also. This is unsigned
5693
// integer arithmetic, checking carry bit is enough to detect it.
5694
// For variable length array, we did an up-front check already.
5695
if (sizeInReg)
5696
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp2Reg, resReg, sizeReg, iCursor);
5697
else
5698
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, temp2Reg, resReg, allocSize, iCursor);
5699
5700
//TODO: shouldAlignToCacheBoundary is never true, check its effects here.
5701
int32_t padding = shouldAlignToCacheBoundary ? instanceBoundaryForAlignment : 0;
5702
5703
if (!isVariableLen && ((uint32_t) allocSize + padding) > maxSafeSize)
5704
{
5705
if (!shouldAlignToCacheBoundary)
5706
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp2Reg, resReg, iCursor);
5707
else
5708
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp2Reg, temp1Reg, iCursor);
5709
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, callLabel, condReg, iCursor);
5710
}
5711
5712
// We need to make sure that the TLH pointer is bumped correctly to support the Arraylet header.
5713
//
5714
if (generateArraylets && (node->getOpCodeValue() == TR::anewarray || node->getOpCodeValue() == TR::newarray))
5715
{
5716
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, temp2Reg, temp2Reg, TR::Compiler->om.getObjectAlignmentInBytes() - 1, iCursor);
5717
iCursor = generateTrg1Src1Imm2Instruction(cg, comp->target().is64Bit() ? TR::InstOpCode::rldicr : TR::InstOpCode::rlwinm, node, temp2Reg, temp2Reg, 0, int64_t(-TR::Compiler->om.getObjectAlignmentInBytes()), iCursor);
5718
static const char *p = feGetEnv("TR_TarokAlignHeapTopBreak");
5719
if (p)
5720
iCursor = generateInstruction(cg, TR::InstOpCode::bad, node, iCursor);
5721
}
5722
5723
// Ok, temp2Reg now points to where the object will end on the TLH.
5724
// resReg will contain the start of the object where we'll write out our
5725
// J9Class*. Should look like this in memory:
5726
// [heapAlloc == resReg] ... temp2Reg ...//... heapTopReg.
5727
5728
//Here we check if we overflow the TLH Heap Top (heapTop, or nonZeroHeapTop)
5729
//branch to regular heapAlloc Snippet if we overflow (ie callLabel).
5730
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp2Reg, heapTopReg, iCursor);
5731
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, callLabel, condReg, iCursor);
5732
5733
//TODO: this code is never executed, check if we can remove this now.
5734
if (!cg->isDualTLH())
5735
{
5736
//shouldAlignToCacheBoundary is false at definition at the top, and
5737
//the only codepoint where its set to true is never executed
5738
//so this looks like a candidate for deletion.
5739
if (shouldAlignToCacheBoundary)
5740
{
5741
TR::LabelSymbol *doneAlignLabel = generateLabelSymbol(cg);
5742
TR::LabelSymbol *multiSlotGapLabel = generateLabelSymbol(cg);
5743
;
5744
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, dataSizeReg, temp1Reg, resReg, iCursor);
5745
5746
if (sizeInReg)
5747
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, sizeReg, dataSizeReg, sizeReg, iCursor);
5748
else
5749
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, sizeReg, dataSizeReg, allocSize, iCursor);
5750
5751
sizeInReg = true;
5752
5753
iCursor = generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, condReg, dataSizeReg, sizeof(uintptr_t), iCursor);
5754
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, doneAlignLabel, condReg, iCursor);
5755
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, multiSlotGapLabel, condReg, iCursor);
5756
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, dataSizeReg, J9_GC_SINGLE_SLOT_HOLE, iCursor);
5757
5758
if (comp->target().is64Bit() && fej9->generateCompressedLockWord())
5759
{
5760
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, temp1Reg, 0, 4), dataSizeReg, iCursor);
5761
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, temp1Reg, 4, 4), dataSizeReg, iCursor);
5762
}
5763
else
5764
{
5765
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, temp1Reg, 0, TR::Compiler->om.sizeofReferenceAddress()), dataSizeReg,
5766
iCursor);
5767
}
5768
5769
iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, doneAlignLabel, iCursor);
5770
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, multiSlotGapLabel, iCursor);
5771
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, temp1Reg, TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()),
5772
dataSizeReg, iCursor);
5773
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, dataSizeReg, J9_GC_MULTI_SLOT_HOLE, iCursor);
5774
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, temp1Reg, 0, TR::Compiler->om.sizeofReferenceAddress()), dataSizeReg,
5775
iCursor);
5776
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, doneAlignLabel, iCursor);
5777
}
5778
}
5779
5780
if (cg->enableTLHPrefetching())
5781
{
5782
//Decide between zeroed and non-zero TLH'es
5783
5784
if (cg->isDualTLH() && node->canSkipZeroInitialization())
5785
{
5786
5787
if (verboseDualTLH)
5788
fprintf(stderr, "DELETEME genHeapAlloc PREFETCH useNonZeroTLH [%d] isVariableLen [%d] node: [%p] %s [@%s]\n", 1, isVariableLen, node, comp->signature(),
5789
comp->getHotnessName(comp->getMethodHotness()));
5790
5791
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,
5792
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, nonZeroTlhPrefetchFTA), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5793
}
5794
else
5795
{
5796
if (verboseDualTLH)
5797
fprintf(stderr, "DELETEME genHeapAlloc PREFETCH useNonZeroTLH [%d] isVariableLen [%d] node: [%p] %s [@%s]\n", 0, isVariableLen, node, comp->signature(),
5798
comp->getHotnessName(comp->getMethodHotness()));
5799
5800
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,
5801
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, tlhPrefetchFTA), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5802
}
5803
5804
if (sizeInReg)
5805
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::subf_r, node, temp1Reg, sizeReg, temp1Reg, condReg, iCursor);
5806
else
5807
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addic_r, node, temp1Reg, temp1Reg, condReg, -allocSize, iCursor);
5808
5809
//Write back and allocate Snippet if needed.
5810
TR::LabelSymbol * callLabel = NULL;
5811
if (cg->isDualTLH() && node->canSkipZeroInitialization())
5812
{
5813
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,
5814
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, nonZeroTlhPrefetchFTA), TR::Compiler->om.sizeofReferenceAddress()), temp1Reg, iCursor);
5815
5816
callLabel = cg->lookUpSnippet(TR::Snippet::IsNonZeroAllocPrefetch, NULL);
5817
if (callLabel == NULL)
5818
{
5819
callLabel = generateLabelSymbol(cg);
5820
TR::Snippet *snippet = new (cg->trHeapMemory()) TR::PPCNonZeroAllocPrefetchSnippet(cg, node, callLabel);
5821
cg->addSnippet(snippet);
5822
}
5823
}
5824
else
5825
{
5826
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,
5827
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, tlhPrefetchFTA), TR::Compiler->om.sizeofReferenceAddress()), temp1Reg, iCursor);
5828
5829
callLabel = cg->lookUpSnippet(TR::Snippet::IsAllocPrefetch, NULL);
5830
if (callLabel == NULL)
5831
{
5832
callLabel = generateLabelSymbol(cg);
5833
TR::Snippet *snippet = new (cg->trHeapMemory()) TR::PPCAllocPrefetchSnippet(cg, node, callLabel);
5834
cg->addSnippet(snippet);
5835
}
5836
}
5837
5838
// kills temp1Reg and sizeReg
5839
iCursor = generateDepConditionalBranchInstruction(cg, TR::InstOpCode::blel, PPCOpProp_BranchUnlikely, node, callLabel, condReg, dependencies, iCursor);
5840
5841
cg->machine()->setLinkRegisterKilled(true);
5842
}
5843
5844
//Done, write back to heapAlloc (zero or nonZero TLH) here.
5845
if (cg->isDualTLH() && node->canSkipZeroInitialization())
5846
{
5847
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,
5848
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, nonZeroHeapAlloc), TR::Compiler->om.sizeofReferenceAddress()), temp2Reg, iCursor);
5849
}
5850
else
5851
{
5852
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,
5853
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapAlloc), TR::Compiler->om.sizeofReferenceAddress()), temp2Reg, iCursor);
5854
}
5855
}
5856
else
5857
{
5858
bool sizeInReg = (allocSize > UPPER_IMMED);
5859
TR::LabelSymbol *tryLabel = generateLabelSymbol(cg);
5860
5861
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, heapTopReg,
5862
TR::MemoryReference::createWithDisplacement(cg, temp1Reg, offsetof(J9MemorySegment, heapTop), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5863
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, dataSizeReg, temp1Reg, offsetof(J9MemorySegment, heapAlloc), iCursor);
5864
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, zeroReg, 0, iCursor);
5865
if (sizeInReg)
5866
{
5867
if (0x00008000 == HI_VALUE(allocSize))
5868
{
5869
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, node, sizeReg, 0x7FFF, iCursor);
5870
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addis, node, sizeReg, sizeReg, 0x1, iCursor);
5871
}
5872
else
5873
{
5874
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, node, sizeReg, HI_VALUE(allocSize), iCursor);
5875
}
5876
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, sizeReg, sizeReg, LO_VALUE(allocSize), iCursor);
5877
}
5878
5879
// Try to allocate
5880
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, tryLabel, iCursor);
5881
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, resReg, TR::MemoryReference::createWithDisplacement(cg, dataSizeReg, 0, TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5882
5883
// Calculate the after-allocation heapAlloc: if the size is huge,
5884
// we need to check address wrap-around also. This is unsigned
5885
// integer arithmetic, checking carry bit is enough to detect it.
5886
if ((uint32_t) allocSize > maxSafeSize)
5887
{
5888
if (sizeInReg)
5889
{
5890
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp1Reg, resReg, sizeReg, iCursor);
5891
}
5892
else
5893
{
5894
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, temp1Reg, resReg, allocSize, iCursor);
5895
}
5896
5897
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp1Reg, resReg, iCursor);
5898
5899
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, callLabel, condReg, iCursor);
5900
}
5901
else
5902
{
5903
if (sizeInReg)
5904
{
5905
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp1Reg, resReg, sizeReg, iCursor);
5906
}
5907
else
5908
{
5909
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, temp1Reg, resReg, allocSize, iCursor);
5910
}
5911
}
5912
5913
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp1Reg, heapTopReg, iCursor);
5914
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, callLabel, condReg, iCursor);
5915
5916
// todo64: I think these need to be ldarx/stdcx. in 64-bit mode
5917
iCursor = generateTrg1MemInstruction(cg, TR::InstOpCode::lwarx, node, temp2Reg, TR::MemoryReference::createWithIndexReg(cg, dataSizeReg, zeroReg, 4), iCursor);
5918
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::cmpl4, node, condReg, temp2Reg, resReg, iCursor);
5919
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, tryLabel, condReg, iCursor);
5920
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stwcx_r, node, TR::MemoryReference::createWithIndexReg(cg, dataSizeReg, zeroReg, 4), temp1Reg, iCursor);
5921
5922
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, tryLabel, condReg, iCursor);
5923
}
5924
}
5925
}
5926
5927
5928
static void genInitObjectHeader(TR::Node *node, TR::Instruction *&iCursor, TR_OpaqueClassBlock *clazz, TR::Register *classReg, TR::Register *resReg, TR::Register *zeroReg,
5929
TR::Register *condReg, TR::Register *temp1Reg, TR::Register *temp2Reg, TR::Register * packedClobberedOffset, TR::RegisterDependencyConditions *conditions, bool needZeroInit,
5930
TR::CodeGenerator *cg)
5931
{
5932
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
5933
J9ROMClass *romClass = 0;
5934
uint32_t staticFlag = 0;
5935
uint32_t orFlag = 0;
5936
TR::Compilation *comp = cg->comp();
5937
5938
TR_ASSERT(clazz, "Cannot have a null OpaqueClassBlock\n");
5939
romClass = TR::Compiler->cls.romClassOf(clazz);
5940
staticFlag = romClass->instanceShape;
5941
TR::Register *metaReg = cg->getMethodMetaDataRegister();
5942
5943
TR::Register * clzReg = classReg;
5944
5945
if (comp->compileRelocatableCode() && !comp->getOption(TR_UseSymbolValidationManager))
5946
{
5947
if (node->getOpCodeValue() == TR::newarray)
5948
{
5949
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,
5950
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, javaVM), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5951
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,
5952
TR::MemoryReference::createWithDisplacement(cg, temp1Reg, ((TR_J9VM *) fej9)->getPrimitiveArrayOffsetInJavaVM(node->getSecondChild()->getInt()),
5953
TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5954
clzReg = temp1Reg;
5955
}
5956
else if (node->getOpCodeValue() == TR::anewarray)
5957
{
5958
TR_ASSERT(classReg, "must have a classReg for TR::anewarray in AOT mode");
5959
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,
5960
TR::MemoryReference::createWithDisplacement(cg, classReg, offsetof(J9Class, arrayClass), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5961
clzReg = temp1Reg;
5962
}
5963
else
5964
{
5965
TR_ASSERT(node->getOpCodeValue() == TR::New && classReg, "must have a classReg for TR::New in AOT mode");
5966
clzReg = classReg;
5967
}
5968
}
5969
5970
// Store the class
5971
if (clzReg == NULL)
5972
{
5973
// HCR in genInitObjectHeader
5974
if (cg->wantToPatchClassPointer(clazz, node))
5975
{
5976
iCursor = loadAddressConstantInSnippet(cg, node, (int64_t) clazz, temp1Reg, temp2Reg,TR::InstOpCode::Op_load, false, iCursor);
5977
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, temp1Reg, temp1Reg, orFlag, iCursor);
5978
}
5979
else
5980
{
5981
#ifdef TR_TARGET_64BIT
5982
int32_t offset;
5983
intptr_t classPtr = (intptr_t)clazz;
5984
5985
offset = TR_PPCTableOfConstants::lookUp((int8_t *)&classPtr, sizeof(intptr_t), true, 0, cg);
5986
5987
if (offset != PTOC_FULL_INDEX)
5988
{
5989
offset *= TR::Compiler->om.sizeofReferenceAddress();
5990
if (TR_PPCTableOfConstants::getTOCSlot(offset) == 0)
5991
TR_PPCTableOfConstants::setTOCSlot(offset, (int64_t)clazz);
5992
if (offset<LOWER_IMMED||offset>UPPER_IMMED)
5993
{
5994
TR_ASSERT_FATAL_WITH_NODE(node, 0x00008000 != HI_VALUE(offset), "TOC offset (0x%x) is unexpectedly high. Can not encode upper 16 bits into an addis instruction.", offset);
5995
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addis, node, temp1Reg, cg->getTOCBaseRegister(), HI_VALUE(offset), iCursor);
5996
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg, TR::MemoryReference::createWithDisplacement(cg, temp1Reg, LO_VALUE(offset), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
5997
}
5998
else
5999
{
6000
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg, TR::MemoryReference::createWithDisplacement(cg, cg->getTOCBaseRegister(), offset, TR::Compiler->om.sizeofReferenceAddress()), iCursor);
6001
}
6002
if (orFlag != 0)
6003
{
6004
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, temp1Reg, temp1Reg, orFlag, iCursor);
6005
}
6006
}
6007
else
6008
{
6009
iCursor = loadConstant(cg, node, (int64_t)clazz|(int64_t)orFlag, temp1Reg, iCursor);
6010
}
6011
#else
6012
iCursor = loadConstant(cg, node, (int32_t) clazz | (int32_t) orFlag, temp1Reg, iCursor);
6013
#endif /* TR_TARGET_64BIT */
6014
}
6015
if (TR::Compiler->om.compressObjectReferences())
6016
// must store only 32 bits
6017
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node,
6018
TR::MemoryReference::createWithDisplacement(cg, resReg, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), 4),
6019
temp1Reg, iCursor);
6020
else
6021
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,
6022
TR::MemoryReference::createWithDisplacement(cg, resReg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), TR::Compiler->om.sizeofReferenceAddress()), temp1Reg, iCursor);
6023
}
6024
else
6025
{
6026
if (orFlag != 0)
6027
{
6028
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, clzReg, clzReg, orFlag, iCursor);
6029
}
6030
if (TR::Compiler->om.compressObjectReferences())
6031
// must store only 32 bits
6032
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node,
6033
TR::MemoryReference::createWithDisplacement(cg, resReg, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), 4),
6034
clzReg, iCursor);
6035
else
6036
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,
6037
TR::MemoryReference::createWithDisplacement(cg, resReg, (int32_t) TR::Compiler->om.offsetOfObjectVftField(), TR::Compiler->om.sizeofReferenceAddress()), clzReg, iCursor);
6038
}
6039
6040
6041
#ifndef J9VM_INTERP_FLAGS_IN_CLASS_SLOT
6042
6043
bool isStaticFlag = fej9->isStaticObjectFlags();
6044
if (isStaticFlag)
6045
{
6046
// The object flags can be determined at compile time.
6047
staticFlag |= fej9->getStaticObjectFlags();
6048
if (staticFlag != 0 || needZeroInit)
6049
{
6050
iCursor = loadConstant(cg, node, (int32_t) staticFlag, temp2Reg, iCursor);
6051
// Store the flags
6052
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, new (cg->trHeapMemory()) TR::MemoryReference(resReg, (int32_t) TMP_OFFSETOF_J9OBJECT_FLAGS, 4, cg), temp2Reg,
6053
iCursor);
6054
}
6055
}
6056
else if (!comp->getOptions()->realTimeGC())
6057
{
6058
// If the object flags cannot be determined at compile time, we add a load for it.
6059
//
6060
iCursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp2Reg,
6061
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, allocateThreadLocalHeap.objectFlags), TR::Compiler->om.sizeofReferenceAddress()), iCursor);
6062
6063
// OR staticFlag with temp2Reg.
6064
// For now, only the lower 16 bits are set in staticFlag. But check the higher 16 bits just in case.
6065
if (staticFlag != 0)
6066
{
6067
if ((staticFlag & 0xFFFF0000) != 0)
6068
{
6069
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::oris, node, temp2Reg, temp2Reg, (staticFlag >> 16) & 0x0000FFFF, iCursor);
6070
}
6071
if ((staticFlag & 0x0000FFFF) != 0)
6072
{
6073
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, temp2Reg, temp2Reg, staticFlag & 0x0000FFFF, iCursor);
6074
}
6075
}
6076
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, resReg, (int32_t) TMP_OFFSETOF_J9OBJECT_FLAGS, 4), temp2Reg,
6077
iCursor);
6078
}
6079
6080
#endif /*J9VM_INTERP_FLAGS_IN_CLASS_SLOT*/
6081
6082
TR::InstOpCode::Mnemonic storeOpCode;
6083
int32_t lockSize;
6084
6085
if (comp->target().is64Bit() && !fej9->generateCompressedLockWord())
6086
{
6087
storeOpCode = TR::InstOpCode::std;
6088
lockSize = 8;
6089
}
6090
else
6091
{
6092
storeOpCode = TR::InstOpCode::stw;
6093
lockSize = 4;
6094
}
6095
6096
int32_t lwOffset = fej9->getByteOffsetToLockword(clazz);
6097
if (clazz && (lwOffset > 0))
6098
{
6099
int32_t lwInitialValue = fej9->getInitialLockword(clazz);
6100
6101
if (0 != lwInitialValue)
6102
{
6103
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, temp1Reg, lwInitialValue, iCursor);
6104
iCursor = generateMemSrc1Instruction(cg, storeOpCode, node, TR::MemoryReference::createWithDisplacement(cg, resReg, lwOffset, lockSize), temp1Reg, iCursor);
6105
}
6106
}
6107
}
6108
6109
static void genAlignArray(TR::Node *node, TR::Instruction *&iCursor, bool isVariableLen, TR::Register *resReg, int32_t objectSize, int32_t dataBegin, TR::Register *dataSizeReg,
6110
TR::Register *condReg, TR::Register *temp1Reg, TR::Register *temp2Reg, TR::CodeGenerator *cg)
6111
{
6112
TR::LabelSymbol *slotAtStart = generateLabelSymbol(cg);
6113
TR::LabelSymbol *doneAlign = generateLabelSymbol(cg);
6114
6115
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::andi_r, node, temp1Reg, resReg, condReg, 7, iCursor);
6116
iCursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, temp2Reg, 3, iCursor);
6117
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, slotAtStart, condReg, iCursor);
6118
6119
// The slop bytes are at the end of the allocated object.
6120
if (isVariableLen)
6121
{
6122
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp1Reg, resReg, dataSizeReg, iCursor);
6123
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, temp1Reg, dataBegin, 4), temp2Reg, iCursor);
6124
}
6125
else if (objectSize > UPPER_IMMED)
6126
{
6127
iCursor = loadConstant(cg, node, objectSize, temp1Reg, iCursor);
6128
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithIndexReg(cg, resReg, temp1Reg, 4), temp2Reg, iCursor);
6129
}
6130
else
6131
{
6132
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, resReg, objectSize, 4), temp2Reg, iCursor);
6133
}
6134
iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, doneAlign, iCursor);
6135
6136
// the slop bytes are at the start of the allocation
6137
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, slotAtStart, iCursor);
6138
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, resReg, (int32_t) 0, 4), temp2Reg, iCursor);
6139
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, resReg, resReg, 4, iCursor);
6140
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, doneAlign, iCursor);
6141
}
6142
6143
static void genInitArrayHeader(TR::Node *node, TR::Instruction *&iCursor, bool isVariableLen, TR_OpaqueClassBlock *clazz, TR::Register *classReg, TR::Register *resReg,
6144
TR::Register *zeroReg, TR::Register *condReg, TR::Register *eNumReg, TR::Register *dataSizeReg, TR::Register *temp1Reg, TR::Register *temp2Reg,
6145
TR::RegisterDependencyConditions *conditions, bool needZeroInit, TR::CodeGenerator *cg)
6146
{
6147
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
6148
TR::Register *instanceSizeReg;
6149
6150
genInitObjectHeader(node, iCursor, clazz, classReg, resReg, zeroReg, condReg, temp1Reg, temp2Reg, NULL, conditions, needZeroInit, cg);
6151
6152
instanceSizeReg = eNumReg;
6153
6154
if ((node->getOpCodeValue() == TR::newarray || node->getOpCodeValue() == TR::anewarray) && node->getFirstChild()->getOpCode().isLoadConst() && (node->getFirstChild()->getInt() == 0))
6155
{// constant zero length non-packed array
6156
// Zero length arrays are discontiguous (i.e. they also need the discontiguous length field to be 0) because
6157
// they are indistinguishable from non-zero length discontiguous arrays
6158
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node,
6159
TR::MemoryReference::createWithDisplacement(cg, resReg, fej9->getOffsetOfDiscontiguousArraySizeField()-4, 4),
6160
instanceSizeReg, iCursor);
6161
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node,
6162
TR::MemoryReference::createWithDisplacement(cg, resReg, fej9->getOffsetOfDiscontiguousArraySizeField(), 4),
6163
instanceSizeReg, iCursor);
6164
}
6165
else
6166
{
6167
// Store the array size
6168
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node,
6169
TR::MemoryReference::createWithDisplacement(cg, resReg, fej9->getOffsetOfContiguousArraySizeField(), 4),
6170
instanceSizeReg, iCursor);
6171
}
6172
}
6173
6174
static void genZeroInit(TR::CodeGenerator *cg, TR::Node *node, TR::Register *objectReg, int32_t headerSize, int32_t totalSize, bool useInitInfo)
6175
{
6176
TR_ASSERT((totalSize - headerSize > 0) && ((totalSize - headerSize) % 4 == 0), "Expecting non-zero word-aligned data size");
6177
6178
TR::Register *zeroReg = cg->allocateRegister();
6179
TR::Compilation* comp = cg->comp();
6180
6181
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, zeroReg, 0);
6182
6183
// Perform initialization if it is needed:
6184
// 1) Initialize certain array elements individually. This depends on the optimizer
6185
// providing a "short" list of individual indices;
6186
// 2) Initialize the whole array:
6187
// a) If the object size is constant and small use straight line code;
6188
// b) For large objects and variable length arrays, do nothing, it was handled in the allocation helper.
6189
if (useInitInfo)
6190
{
6191
TR_ExtraInfoForNew *initInfo = node->getSymbolReference()->getExtraInfo();
6192
6193
TR_ASSERT(initInfo && initInfo->zeroInitSlots && initInfo->numZeroInitSlots > 0, "Expecting valid init info");
6194
6195
TR_BitVectorIterator bvi(*initInfo->zeroInitSlots);
6196
if (comp->target().is64Bit())
6197
{
6198
int32_t lastNotInit = -1;
6199
int32_t currElem = -1;
6200
6201
// Try to group set of words into smallest groupings using double-word stores (where possible)
6202
while (bvi.hasMoreElements())
6203
{
6204
currElem = bvi.getNextElement();
6205
6206
if (lastNotInit == -1)
6207
{
6208
// currently looking at only one slot (either just starting, or just emitted double-word store in last iter)
6209
lastNotInit = currElem;
6210
}
6211
else if (currElem == lastNotInit + 1)
6212
{
6213
// consecutive slots, can use std
6214
generateMemSrc1Instruction(cg, TR::InstOpCode::std, node, TR::MemoryReference::createWithDisplacement(cg, objectReg, headerSize + lastNotInit * 4, 8), zeroReg);
6215
lastNotInit = -1;
6216
}
6217
else
6218
{
6219
// Two non-consecutive slots, use stw for earlier slot and keep looking for slot
6220
// consecutive with the second slot currently held
6221
generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, objectReg, headerSize + lastNotInit * 4, 4), zeroReg);
6222
lastNotInit = currElem;
6223
}
6224
}
6225
6226
if (lastNotInit != -1)
6227
{
6228
// Last slot is not consecutive with other slots, hasn't been initialized yet
6229
generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, objectReg, headerSize + lastNotInit * 4, 4), zeroReg);
6230
}
6231
}
6232
else
6233
{
6234
while (bvi.hasMoreElements())
6235
{
6236
generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node,
6237
TR::MemoryReference::createWithDisplacement(cg, objectReg, headerSize + bvi.getNextElement() * TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()), zeroReg);
6238
}
6239
}
6240
}
6241
else
6242
{
6243
int32_t ofs;
6244
for (ofs = headerSize; ofs < totalSize - TR::Compiler->om.sizeofReferenceAddress(); ofs += TR::Compiler->om.sizeofReferenceAddress())
6245
{
6246
generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, objectReg, ofs, TR::Compiler->om.sizeofReferenceAddress()), zeroReg);
6247
}
6248
if (ofs + 4 == totalSize)
6249
generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, objectReg, ofs, 4), zeroReg);
6250
else if (ofs + 8 == totalSize)
6251
generateMemSrc1Instruction(cg, TR::InstOpCode::std, node, TR::MemoryReference::createWithDisplacement(cg, objectReg, ofs, 8), zeroReg);
6252
}
6253
6254
// Scheduling barrier
6255
generateLabelInstruction(cg, TR::InstOpCode::label, node, generateLabelSymbol(cg));
6256
6257
cg->stopUsingRegister(zeroReg);
6258
}
6259
6260
TR::Register *J9::Power::TreeEvaluator::VMnewEvaluator(TR::Node *node, TR::CodeGenerator *cg)
6261
{
6262
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
6263
int32_t allocateSize, objectSize, dataBegin, idx;
6264
TR::ILOpCodes opCode;
6265
TR_OpaqueClassBlock *clazz;
6266
TR::Register *classReg, *resReg, *zeroReg = NULL;
6267
TR::RealRegister::RegNum resultRealReg = TR::RealRegister::gr8;
6268
TR::Register *condReg, *callResult, *enumReg, *dataSizeReg;
6269
TR::Register *tmp3Reg = NULL, *tmp4Reg, *tmp5Reg, *tmp6Reg, *tmp7Reg = NULL;
6270
TR::Register *packedRegAddr, *packedRegOffs, *packedRegLength;
6271
TR::LabelSymbol *callLabel, *callReturnLabel, *doneLabel;
6272
TR::RegisterDependencyConditions *conditions;
6273
TR::Instruction *iCursor = NULL;
6274
bool doInline = true, isArray = false, doublewordAlign = false;
6275
bool isVariableLen;
6276
bool insertType = false;
6277
static bool TR_noThreadLocalHeap = feGetEnv("TR_noThreadLocalHeap") ? 1 : 0;
6278
TR::Compilation * comp = cg->comp();
6279
bool generateArraylets = comp->generateArraylets();
6280
6281
if (comp->getOption(TR_DisableTarokInlineArrayletAllocation) && (node->getOpCodeValue() == TR::anewarray || node->getOpCodeValue() == TR::newarray))
6282
doInline = false;
6283
6284
bool usingTLH = !TR_noThreadLocalHeap;
6285
bool needZeroInit = (!usingTLH || !fej9->tlhHasBeenCleared()) || comp->getOptions()->realTimeGC();
6286
bool isDualTLH = cg->isDualTLH();
6287
6288
int32_t elementSize = 0;
6289
6290
opCode = node->getOpCodeValue();
6291
objectSize = comp->canAllocateInline(node, clazz);
6292
6293
bool isArrayAlloc = (opCode == TR::newarray || opCode == TR::anewarray);
6294
bool isConstantLenArrayAlloc = isArrayAlloc && node->getFirstChild()->getOpCode().isLoadConst();
6295
bool isConstantZeroLenArrayAlloc = isConstantLenArrayAlloc && (node->getFirstChild()->getInt() == 0);
6296
6297
TR_ASSERT(objectSize <= 0 || (objectSize & (TR::Compiler->om.sizeofReferenceAddress() - 1)) == 0, "object size causes an alignment problem");
6298
if (objectSize < 0 || (objectSize == 0 && !usingTLH))
6299
doInline = false;
6300
isVariableLen = (objectSize == 0);
6301
6302
allocateSize = objectSize;
6303
6304
if (opCode == TR::New)
6305
{
6306
if (comp->getOptions()->realTimeGC())
6307
{
6308
if (objectSize > fej9->getMaxObjectSizeForSizeClass())
6309
{
6310
doInline = false;
6311
}
6312
}
6313
}
6314
6315
if (!isVariableLen)
6316
{
6317
allocateSize = (allocateSize + TR::Compiler->om.getObjectAlignmentInBytes() - 1) & (-TR::Compiler->om.getObjectAlignmentInBytes());
6318
}
6319
6320
if (comp->compileRelocatableCode())
6321
{
6322
switch (opCode)
6323
{
6324
case TR::New: break;
6325
case TR::anewarray: break;
6326
case TR::newarray: break;
6327
default: doInline = false; break;
6328
}
6329
}
6330
6331
static int count = 0;
6332
doInline = doInline && performTransformation(comp, "O^O <%3d> Inlining Allocation of %s [0x%p].\n", count++, node->getOpCode().getName(), node);
6333
6334
if (doInline)
6335
{
6336
generateLabelInstruction(cg, TR::InstOpCode::label, node, generateLabelSymbol(cg));
6337
6338
callLabel = generateLabelSymbol(cg);
6339
callReturnLabel = generateLabelSymbol(cg);
6340
doneLabel = generateLabelSymbol(cg);
6341
conditions = createConditionsAndPopulateVSXDeps(cg, 14);
6342
6343
TR::Node *firstChild = node->getFirstChild();
6344
TR::Node *secondChild = NULL;
6345
6346
if (opCode == TR::New)
6347
{
6348
// classReg is passed to the VM helper on the slow path and subsequently clobbered; copy it for later nodes if necessary
6349
classReg = cg->gprClobberEvaluate(firstChild);
6350
dataBegin = TR::Compiler->om.objectHeaderSizeInBytes();
6351
}
6352
else
6353
{
6354
TR_ASSERT(opCode == TR::newarray || opCode == TR::anewarray, "Bad opCode for VMnewEvaluator");
6355
isArray = true;
6356
if (generateArraylets || TR::Compiler->om.useHybridArraylets())
6357
{
6358
if (node->getOpCodeValue() == TR::newarray)
6359
elementSize = TR::Compiler->om.getSizeOfArrayElement(node);
6360
else if (comp->useCompressedPointers())
6361
elementSize = TR::Compiler->om.sizeofReferenceField();
6362
else
6363
elementSize = TR::Compiler->om.sizeofReferenceAddress();
6364
6365
if (generateArraylets)
6366
dataBegin = fej9->getArrayletFirstElementOffset(elementSize, comp);
6367
else
6368
dataBegin = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();
6369
static const char *p = feGetEnv("TR_TarokDataBeginBreak");
6370
if (p)
6371
TR_ASSERT(false, "Hitting Arraylet Data Begin Break");
6372
}
6373
else
6374
{
6375
dataBegin = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();
6376
}
6377
secondChild = node->getSecondChild();
6378
enumReg = cg->evaluate(firstChild);
6379
6380
insertType = (opCode == TR::newarray && secondChild->getDataType() == TR::Int32 && secondChild->getReferenceCount() == 1 && secondChild->getOpCode().isLoadConst());
6381
6382
if (comp->compileRelocatableCode() && comp->getOption(TR_UseSymbolValidationManager))
6383
{
6384
// IMPORTANT: secondChild actually references the J9Class of the array *elements* rather
6385
// than the J9Class of the array itself; the new AOT infrastructure requires that
6386
// classReg contain the J9Class of the array, so we have to actually construct a new
6387
// loadaddr for that and then evaluate it instead of evaluating secondChild directly.
6388
// Note that the original secondChild *must still be evaluated* as it will be used in
6389
// the out-of-line code section.
6390
TR::StaticSymbol *classSymbol = TR::StaticSymbol::create(comp->trHeapMemory(), TR::Address);
6391
classSymbol->setStaticAddress(clazz);
6392
classSymbol->setClassObject();
6393
6394
cg->evaluate(secondChild);
6395
secondChild = TR::Node::createWithSymRef(TR::loadaddr, 0,
6396
new (comp->trHeapMemory()) TR::SymbolReference(comp->getSymRefTab(), classSymbol));
6397
secondChild->incReferenceCount();
6398
6399
classReg = cg->evaluate(secondChild);
6400
}
6401
else if (insertType)
6402
{
6403
classReg = cg->allocateRegister();
6404
}
6405
else
6406
{
6407
// classReg is passed to the VM helper on the slow path and subsequently clobbered; copy it for later nodes if necessary
6408
classReg = cg->gprClobberEvaluate(secondChild);
6409
}
6410
}
6411
TR::addDependency(conditions, classReg, TR::RealRegister::NoReg, TR_GPR, cg);
6412
conditions->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0();
6413
6414
if (secondChild == NULL)
6415
enumReg = cg->allocateRegister();
6416
TR::addDependency(conditions, enumReg, TR::RealRegister::NoReg, TR_GPR, cg);
6417
conditions->getPostConditions()->getRegisterDependency(1)->setExcludeGPR0();
6418
6419
condReg = cg->allocateRegister(TR_CCR);
6420
TR::addDependency(conditions, condReg, TR::RealRegister::cr0, TR_CCR, cg);
6421
tmp6Reg = cg->allocateRegister();
6422
TR::addDependency(conditions, tmp6Reg, TR::RealRegister::NoReg, TR_GPR, cg);
6423
tmp4Reg = cg->allocateRegister();
6424
TR::addDependency(conditions, tmp4Reg, TR::RealRegister::gr11, TR_GPR, cg); // used by TR::PPCAllocPrefetchSnippet
6425
tmp5Reg = cg->allocateRegister();
6426
TR::addDependency(conditions, tmp5Reg, TR::RealRegister::NoReg, TR_GPR, cg);
6427
conditions->getPostConditions()->getRegisterDependency(5)->setExcludeGPR0();
6428
resReg = cg->allocateRegister();
6429
TR::addDependency(conditions, resReg, resultRealReg, TR_GPR, cg); // used by TR::PPCAllocPrefetchSnippet
6430
conditions->getPostConditions()->getRegisterDependency(6)->setExcludeGPR0();
6431
dataSizeReg = cg->allocateRegister();
6432
TR::addDependency(conditions, dataSizeReg, TR::RealRegister::NoReg, TR_GPR, cg);
6433
conditions->getPostConditions()->getRegisterDependency(7)->setExcludeGPR0();
6434
tmp7Reg = cg->allocateRegister();
6435
TR::addDependency(conditions, tmp7Reg, TR::RealRegister::NoReg, TR_GPR, cg);
6436
conditions->getPostConditions()->getRegisterDependency(8)->setExcludeGPR0();
6437
tmp3Reg = cg->allocateRegister();
6438
TR::addDependency(conditions, tmp3Reg, TR::RealRegister::gr10, TR_GPR, cg); // used by TR::PPCAllocPrefetchSnippet
6439
6440
TR::Instruction *firstInstruction = cg->getAppendInstruction();
6441
6442
if (!isDualTLH && needZeroInit)
6443
{
6444
zeroReg = cg->allocateRegister();
6445
TR::addDependency(conditions, zeroReg, TR::RealRegister::NoReg, TR_GPR, cg);
6446
}
6447
6448
if (isVariableLen)
6449
allocateSize += dataBegin;
6450
6451
//Here we set up backout paths if we overflow nonZeroTLH in genHeapAlloc.
6452
//If we overflow the nonZeroTLH, set the destination to the right VM runtime helper (eg jitNewObjectNoZeroInit, etc...)
6453
//The zeroed-TLH versions have their correct destinations already setup in TR_ByteCodeIlGenerator::genNew, TR_ByteCodeIlGenerator::genNewArray, TR_ByteCodeIlGenerator::genANewArray
6454
//To retrieve the destination node->getSymbolReference() is used below after genHeapAlloc.
6455
if (isDualTLH && node->canSkipZeroInitialization())
6456
{
6457
// For value types, the backout path should call jitNewValue helper call which is set up before code gen
6458
if ((node->getOpCodeValue() == TR::New)
6459
&& (!TR::Compiler->om.areValueTypesEnabled() || (node->getSymbolReference() != comp->getSymRefTab()->findOrCreateNewValueSymbolRef(comp->getMethodSymbol()))))
6460
node->setSymbolReference(comp->getSymRefTab()->findOrCreateNewObjectNoZeroInitSymbolRef(comp->getMethodSymbol()));
6461
else if (node->getOpCodeValue() == TR::newarray)
6462
node->setSymbolReference(comp->getSymRefTab()->findOrCreateNewArrayNoZeroInitSymbolRef(comp->getMethodSymbol()));
6463
else if (node->getOpCodeValue() == TR::anewarray)
6464
node->setSymbolReference(comp->getSymRefTab()->findOrCreateANewArrayNoZeroInitSymbolRef(comp->getMethodSymbol()));
6465
}
6466
6467
// On return, zeroReg is set to 0 if needZeroInit is true, and
6468
// dataSizeReg is set to the size of data area if isVariableLen
6469
// is true, and either elementSize != 1 or needZeroInit is true
6470
// (and we only ever use dataSizeReg below in those cases).
6471
genHeapAlloc(node, iCursor, clazz, isVariableLen, enumReg, classReg, resReg, zeroReg, condReg, dataSizeReg, tmp5Reg, tmp4Reg, tmp3Reg, tmp6Reg, tmp7Reg, callLabel, doneLabel, allocateSize, elementSize,
6472
usingTLH, needZeroInit, conditions, cg);
6473
6474
// Call out to VM runtime helper if needed.
6475
TR::Register *objReg = cg->allocateCollectedReferenceRegister();
6476
TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::acall, objReg, callLabel, callReturnLabel, cg);
6477
cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);
6478
6479
if (isArray)
6480
{
6481
// Align the array if necessary.
6482
if (doublewordAlign && !comp->getOptions()->realTimeGC())
6483
genAlignArray(node, iCursor, isVariableLen, resReg, objectSize, dataBegin, dataSizeReg, condReg, tmp5Reg, tmp4Reg, cg);
6484
if (comp->compileRelocatableCode() && (opCode == TR::anewarray || comp->getOption(TR_UseSymbolValidationManager)))
6485
genInitArrayHeader(node, iCursor, isVariableLen, clazz, classReg, resReg, zeroReg, condReg, enumReg, dataSizeReg, tmp5Reg, tmp4Reg, conditions, needZeroInit, cg);
6486
else
6487
genInitArrayHeader(node, iCursor, isVariableLen, clazz, NULL, resReg, zeroReg, condReg, enumReg, dataSizeReg,
6488
tmp5Reg, tmp4Reg, conditions, needZeroInit, cg);
6489
6490
#ifdef TR_TARGET_64BIT
6491
/* Here we'll update dataAddr slot for both fixed and variable length arrays. Fixed length arrays are
6492
* simple as we just need to check first child of the node for array size. For variable length arrays
6493
* runtime size checks are needed to determine whether to use contiguous or discontiguous header layout.
6494
*
6495
* In both scenarios, arrays of non-zero size use contiguous header layout while zero size arrays use
6496
* discontiguous header layout.
6497
*/
6498
TR::Register *offsetReg = tmp5Reg;
6499
TR::Register *firstDataElementReg = tmp4Reg;
6500
TR::MemoryReference *dataAddrSlotMR = NULL;
6501
6502
if (isVariableLen && TR::Compiler->om.compressObjectReferences())
6503
{
6504
/* We need to check enumReg at runtime to determine correct offset of dataAddr field.
6505
* Here we deal only with compressed refs because dataAddr offset for discontiguous
6506
* and contiguous arrays is the same in full refs.
6507
*/
6508
if (comp->getOption(TR_TraceCG))
6509
traceMsg(comp, "Node (%p): Dealing with compressed refs variable length array.\n", node);
6510
6511
TR_ASSERT_FATAL_WITH_NODE(node, (fej9->getOffsetOfDiscontiguousDataAddrField() - fej9->getOffsetOfContiguousDataAddrField()) == 8,
6512
"Offset of dataAddr field in discontiguous array is expected to be 8 bytes more than contiguous array. But was %d bytes for discontigous and %d bytes for contiguous array.\n", fej9->getOffsetOfDiscontiguousDataAddrField(), fej9->getOffsetOfContiguousDataAddrField());
6513
6514
iCursor = generateTrg1Src1Instruction(cg, TR::InstOpCode::cntlzd, node, offsetReg, enumReg, iCursor);
6515
iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, offsetReg, offsetReg, 29, 8, iCursor);
6516
// offsetReg should either be 0 (if enumReg > 0) or 8 (if enumReg == 0)
6517
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, offsetReg, resReg, offsetReg, iCursor);
6518
6519
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, firstDataElementReg, offsetReg, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), iCursor);
6520
dataAddrSlotMR = TR::MemoryReference::createWithDisplacement(cg, offsetReg, fej9->getOffsetOfContiguousDataAddrField(), TR::Compiler->om.sizeofReferenceAddress());
6521
}
6522
else if (!isVariableLen && node->getFirstChild()->getOpCode().isLoadConst() && node->getFirstChild()->getInt() == 0)
6523
{
6524
if (comp->getOption(TR_TraceCG))
6525
traceMsg(comp, "Node (%p): Dealing with full/compressed refs fixed length zero size array.\n", node);
6526
6527
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, firstDataElementReg, resReg, TR::Compiler->om.discontiguousArrayHeaderSizeInBytes(), iCursor);
6528
dataAddrSlotMR = TR::MemoryReference::createWithDisplacement(cg, resReg, fej9->getOffsetOfDiscontiguousDataAddrField(), TR::Compiler->om.sizeofReferenceAddress());
6529
}
6530
else
6531
{
6532
if (comp->getOption(TR_TraceCG))
6533
traceMsg(comp, "Node (%p): Dealing with either full/compressed refs fixed length non-zero size array or full refs variable length array.\n", node);
6534
6535
if (!TR::Compiler->om.compressObjectReferences())
6536
TR_ASSERT_FATAL_WITH_NODE(node, fej9->getOffsetOfDiscontiguousDataAddrField() == fej9->getOffsetOfContiguousDataAddrField(), "dataAddr field offset is expected to be same for both contiguous and discontiguous arrays in full refs. But was %d bytes for discontiguous and %d bytes for contiguous array.\n", fej9->getOffsetOfDiscontiguousDataAddrField(), fej9->getOffsetOfContiguousDataAddrField());
6537
6538
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, firstDataElementReg, resReg, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), iCursor);
6539
dataAddrSlotMR = TR::MemoryReference::createWithDisplacement(cg, resReg, fej9->getOffsetOfContiguousDataAddrField(), TR::Compiler->om.sizeofReferenceAddress());
6540
}
6541
6542
// store the first data element address to dataAddr slot
6543
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::std, node, dataAddrSlotMR, firstDataElementReg, iCursor);
6544
#endif /* TR_TARGET_64BIT */
6545
6546
if (generateArraylets)
6547
{
6548
//write arraylet pointer to object header
6549
static const char *p = feGetEnv("TR_TarokPreWritePointerBreak");
6550
if (p)
6551
generateInstruction(cg, TR::InstOpCode::bad, node);
6552
6553
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp4Reg, resReg, dataBegin, iCursor);
6554
if (TR::Compiler->om.compressedReferenceShiftOffset() > 0)
6555
iCursor = generateShiftRightLogicalImmediateLong(cg, node, tmp4Reg, tmp4Reg, TR::Compiler->om.compressedReferenceShiftOffset(), iCursor);
6556
iCursor = generateMemSrc1Instruction(cg, (comp->target().is64Bit() && !comp->useCompressedPointers()) ? TR::InstOpCode::std : TR::InstOpCode::stw, node,
6557
TR::MemoryReference::createWithDisplacement(cg, resReg, fej9->getFirstArrayletPointerOffset(comp), comp->useCompressedPointers() ? 4 : TR::Compiler->om.sizeofReferenceAddress()), tmp4Reg, iCursor);
6558
static const char *p1 = feGetEnv("TR_TarokPostWritePointerBreak");
6559
if (p1)
6560
generateInstruction(cg, TR::InstOpCode::bad, node);
6561
}
6562
}
6563
else
6564
{
6565
genInitObjectHeader(node, iCursor, clazz, classReg, resReg, zeroReg, condReg, tmp5Reg, tmp4Reg, packedRegOffs, conditions, needZeroInit, cg);
6566
}
6567
6568
//Do not need zero init if using dualTLH now.
6569
if (!isDualTLH && needZeroInit && (!isConstantZeroLenArrayAlloc))
6570
{
6571
// Perform initialization if it is needed:
6572
// 1) Initialize certain array elements individually. This depends on the optimizer
6573
// providing a "short" list of individual indices;
6574
// 2) Initialize the whole array:
6575
// a) If the object size is constant, we can choose strategy depending on the
6576
// size of the array. Using straight line of code, or unrolled loop;
6577
// b) For variable length of array, do a counted loop;
6578
6579
TR_ExtraInfoForNew *initInfo = node->getSymbolReference()->getExtraInfo();
6580
6581
static bool disableFastArrayZeroInit = (feGetEnv("TR_DisableFastArrayZeroInit") != NULL);
6582
6583
if (!node->canSkipZeroInitialization() && (initInfo == NULL || initInfo->numZeroInitSlots > 0))
6584
{
6585
if (!isVariableLen)
6586
{
6587
if (initInfo != NULL && initInfo->zeroInitSlots != NULL && initInfo->numZeroInitSlots <= 9 && objectSize <= UPPER_IMMED)
6588
{
6589
TR_BitVectorIterator bvi(*initInfo->zeroInitSlots);
6590
6591
if (comp->target().is64Bit())
6592
{
6593
int32_t lastNotInit = -1;
6594
int32_t currElem = -1;
6595
6596
// Try to group set of words into smallest groupings using double-word stores (where possible)
6597
while (bvi.hasMoreElements())
6598
{
6599
currElem = bvi.getNextElement();
6600
6601
if (lastNotInit == -1)
6602
{
6603
// currently looking at only one slot (either just starting, or just emitted double-word store in last iter)
6604
lastNotInit = currElem;
6605
}
6606
else if (currElem == lastNotInit + 1)
6607
{
6608
// consecutive slots, can use std
6609
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::std, node, TR::MemoryReference::createWithDisplacement(cg, resReg, lastNotInit * 4 + dataBegin, 8),
6610
zeroReg, iCursor);
6611
6612
lastNotInit = -1;
6613
}
6614
else
6615
{
6616
// Two non-consecutive slots, use stw for earlier slot and keep looking for slot
6617
// consecutive with the second slot currently held
6618
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, resReg, lastNotInit * 4 + dataBegin, 4),
6619
zeroReg, iCursor);
6620
6621
lastNotInit = currElem;
6622
}
6623
}
6624
6625
if (lastNotInit != -1)
6626
{
6627
// Last slot is not consecutive with other slots, hasn't been initialized yet
6628
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, resReg, lastNotInit * 4 + dataBegin, 4),
6629
zeroReg, iCursor);
6630
}
6631
}
6632
else
6633
{
6634
while (bvi.hasMoreElements())
6635
{
6636
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node,
6637
TR::MemoryReference::createWithDisplacement(cg, resReg, bvi.getNextElement() * 4 + dataBegin, 4), zeroReg, iCursor);
6638
}
6639
}
6640
}
6641
else if (objectSize <= (TR::Compiler->om.sizeofReferenceAddress() * 12))
6642
{
6643
for (idx = dataBegin; idx < (objectSize - TR::Compiler->om.sizeofReferenceAddress()); idx += TR::Compiler->om.sizeofReferenceAddress())
6644
{
6645
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, resReg, idx, TR::Compiler->om.sizeofReferenceAddress()), zeroReg,
6646
iCursor);
6647
}
6648
if (idx + 4 == objectSize)
6649
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, resReg, idx, 4), zeroReg, iCursor);
6650
else if (idx + 8 == objectSize)
6651
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::std, node, TR::MemoryReference::createWithDisplacement(cg, resReg, idx, 8), zeroReg, iCursor);
6652
}
6653
else
6654
{
6655
static bool disableUnrollNewInitLoop1 = (feGetEnv("TR_DisableUnrollNewInitLoop1") != NULL);
6656
if (!disableUnrollNewInitLoop1)
6657
{
6658
int32_t unrollFactor = 8;
6659
int32_t width = comp->target().is64Bit() ? 8 : 4;
6660
int32_t loopCount = (objectSize - dataBegin) / (unrollFactor * width);
6661
int32_t res1 = (objectSize - dataBegin) % (unrollFactor * width);
6662
int32_t residueCount = res1 / width;
6663
int32_t res2 = res1 % width;
6664
TR::LabelSymbol *loopStart = generateLabelSymbol(cg);
6665
6666
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp4Reg, resReg, dataBegin, iCursor);
6667
if (loopCount > 0)
6668
{
6669
if (loopCount > 1)
6670
{
6671
iCursor = loadConstant(cg, node, loopCount, tmp5Reg, iCursor);
6672
iCursor = generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, tmp5Reg, 0, iCursor);
6673
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, loopStart, iCursor);
6674
}
6675
6676
for (int32_t i = 0; i < unrollFactor; i++)
6677
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, i * width, width), zeroReg, iCursor);
6678
6679
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, tmp4Reg, tmp4Reg, (unrollFactor * width), iCursor);
6680
if (loopCount > 1)
6681
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bdnz, node, loopStart, condReg, iCursor);
6682
}
6683
6684
for (int32_t i = 0; i < residueCount; i++)
6685
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, i * width, width), zeroReg, iCursor);
6686
6687
if (res2 && residueCount != 0)
6688
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, tmp4Reg, tmp4Reg, residueCount * width, iCursor);
6689
6690
if (comp->target().is64Bit() && res2 >= 4) // Should only be 0 or 4 here
6691
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, 0, 4), zeroReg, iCursor);
6692
}
6693
else
6694
{
6695
int32_t loopCnt = (objectSize - dataBegin) >> 4;
6696
int32_t residue = ((objectSize - dataBegin) >> 2) & 0x03;
6697
TR::LabelSymbol *initLoop = generateLabelSymbol(cg);
6698
6699
iCursor = loadConstant(cg, node, loopCnt, tmp5Reg, iCursor);
6700
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp4Reg, resReg, dataBegin, iCursor);
6701
iCursor = generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, tmp5Reg, 0, iCursor);
6702
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, initLoop, iCursor);
6703
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, 0, TR::Compiler->om.sizeofReferenceAddress()), zeroReg,
6704
iCursor);
6705
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,
6706
TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, TR::Compiler->om.sizeofReferenceAddress(), TR::Compiler->om.sizeofReferenceAddress()), zeroReg, iCursor);
6707
if (comp->target().is32Bit())
6708
{
6709
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, 8, 4), zeroReg, iCursor);
6710
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, 12, 4), zeroReg, iCursor);
6711
}
6712
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp4Reg, tmp4Reg, 16, iCursor);
6713
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bdnz, node, initLoop, condReg, iCursor);
6714
6715
idx = 0;
6716
if (residue & 0x2)
6717
{
6718
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, 0, TR::Compiler->om.sizeofReferenceAddress()), zeroReg,
6719
iCursor);
6720
6721
if (comp->target().is32Bit())
6722
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, 4, 4), zeroReg, iCursor);
6723
6724
idx = 8;
6725
}
6726
if (residue & 0x1)
6727
{
6728
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, idx, 4), zeroReg, iCursor);
6729
}
6730
}
6731
}
6732
}
6733
else // Init variable length array
6734
{
6735
static bool disableUnrollNewInitLoop2 = (feGetEnv("TR_DisableUnrollNewInitLoop2") != NULL);
6736
static bool disableNewZeroInit = (feGetEnv("TR_DisableNewZeroInit") != NULL);
6737
if (!disableUnrollNewInitLoop2)
6738
{
6739
int32_t unrollFactor = 8, i = 1;
6740
int32_t width = comp->target().is64Bit() ? 8 : 4;
6741
TR::LabelSymbol *loopLabel = generateLabelSymbol(cg);
6742
TR::LabelSymbol *resLabel = generateLabelSymbol(cg);
6743
TR::LabelSymbol *left4Label = generateLabelSymbol(cg);
6744
TR::LabelSymbol *resLoopLabel = NULL;
6745
6746
if (!disableNewZeroInit)
6747
resLoopLabel = generateLabelSymbol(cg);
6748
6749
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp5Reg, resReg, (dataBegin - width), iCursor);
6750
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, tmp4Reg, tmp5Reg, dataSizeReg, iCursor);
6751
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, tmp4Reg, tmp5Reg, iCursor);
6752
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg, iCursor);
6753
6754
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp6Reg, tmp4Reg, (int32_t)(-unrollFactor * width), iCursor);
6755
6756
// Switch order of compare to avoid FXU reject in P6 for later store instruction
6757
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, tmp6Reg, tmp5Reg, iCursor);
6758
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, resLabel, condReg, iCursor);
6759
6760
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel, iCursor);
6761
for (; i <= unrollFactor; i++)
6762
iCursor = generateMemSrc1Instruction(cg, (width == 8) ? TR::InstOpCode::std : TR::InstOpCode::stw, node,
6763
TR::MemoryReference::createWithDisplacement(cg, tmp5Reg, i * width, width), zeroReg, iCursor);
6764
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp5Reg, tmp5Reg, (int32_t)(unrollFactor * width), iCursor);
6765
6766
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, tmp6Reg, tmp5Reg, iCursor);
6767
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, loopLabel, condReg, iCursor);
6768
6769
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, tmp4Reg, tmp5Reg, iCursor);
6770
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg, iCursor);
6771
6772
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, resLabel, iCursor);
6773
6774
if (!disableNewZeroInit)
6775
{
6776
// End pointer-4
6777
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp6Reg, tmp4Reg, -4, iCursor);
6778
6779
// Residue loop start
6780
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, resLoopLabel, iCursor);
6781
6782
// If current pointer == end pointer - 4, there is 4 bytes left to write
6783
// If current pointer > end pointer - 4, data is 8-byte divisible and we are done
6784
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, tmp6Reg, tmp5Reg, iCursor);
6785
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, left4Label, condReg, iCursor);
6786
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, doneLabel, condReg, iCursor);
6787
6788
// Do 8-byte zero init and restart loop
6789
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, tmp5Reg, width, width), zeroReg, iCursor);
6790
6791
if (comp->target().is32Bit())
6792
{
6793
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp5Reg, 8, 4), zeroReg, iCursor);
6794
}
6795
6796
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp5Reg, tmp5Reg, 8, iCursor);
6797
iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, resLoopLabel);
6798
6799
// Finish last 4 bytes if necessary
6800
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, left4Label, iCursor);
6801
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp5Reg, width, 4), zeroReg, iCursor);
6802
}
6803
else
6804
{
6805
/* Need this in 64-bit as well */
6806
iCursor = generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, tmp6Reg, tmp5Reg, tmp4Reg, iCursor);
6807
iCursor = generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, condReg, tmp6Reg, 4, iCursor);
6808
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, left4Label, condReg, iCursor);
6809
6810
iCursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, TR::MemoryReference::createWithDisplacement(cg, tmp5Reg, 8, width), zeroReg, iCursor);
6811
6812
if (comp->target().is32Bit())
6813
{
6814
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp5Reg, 12, 4), zeroReg, iCursor);
6815
}
6816
6817
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp5Reg, tmp5Reg, 8, iCursor);
6818
iCursor = generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, tmp4Reg, tmp5Reg, iCursor);
6819
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg, iCursor);
6820
iCursor = generateLabelInstruction(cg, TR::InstOpCode::b, node, resLabel);
6821
6822
/* Need this in 64-bit as well */
6823
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, left4Label, iCursor);
6824
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp5Reg, 8, 4), zeroReg, iCursor);
6825
}
6826
}
6827
else
6828
{
6829
// Test for zero length array: the following two instructions will be combined
6830
// to the record form by later pass.
6831
iCursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, tmp5Reg, dataSizeReg, 30, 0x3FFFFFFF, iCursor);
6832
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, condReg, tmp5Reg, 0, iCursor);
6833
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, condReg, iCursor);
6834
iCursor = generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, tmp5Reg, 0, iCursor);
6835
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp4Reg, resReg, dataBegin - 4, iCursor);
6836
6837
TR::LabelSymbol *initLoop = generateLabelSymbol(cg);
6838
iCursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, initLoop, iCursor);
6839
iCursor = generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, tmp4Reg, 4, 4), zeroReg, iCursor);
6840
iCursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, tmp4Reg, tmp4Reg, 4, iCursor);
6841
iCursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::bdnz, node, initLoop, condReg, iCursor);
6842
}
6843
}
6844
}
6845
}
6846
6847
if (comp->compileRelocatableCode() && (opCode == TR::New || opCode == TR::anewarray))
6848
{
6849
firstInstruction = firstInstruction->getNext();
6850
TR_OpaqueClassBlock *classToValidate = clazz;
6851
6852
TR_RelocationRecordInformation *recordInfo = (TR_RelocationRecordInformation *) comp->trMemory()->allocateMemory(sizeof(TR_RelocationRecordInformation), heapAlloc);
6853
recordInfo->data1 = allocateSize;
6854
recordInfo->data2 = node->getInlinedSiteIndex();
6855
recordInfo->data3 = (uintptr_t) callLabel;
6856
recordInfo->data4 = (uintptr_t) firstInstruction;
6857
6858
TR::SymbolReference * classSymRef;
6859
TR_ExternalRelocationTargetKind reloKind;
6860
6861
if (opCode == TR::New)
6862
{
6863
classSymRef = node->getFirstChild()->getSymbolReference();
6864
reloKind = TR_VerifyClassObjectForAlloc;
6865
}
6866
else
6867
{
6868
classSymRef = node->getSecondChild()->getSymbolReference();
6869
reloKind = TR_VerifyRefArrayForAlloc;
6870
6871
if (comp->getOption(TR_UseSymbolValidationManager))
6872
classToValidate = comp->fej9()->getComponentClassFromArrayClass(classToValidate);
6873
}
6874
6875
if (comp->getOption(TR_UseSymbolValidationManager))
6876
{
6877
TR_ASSERT_FATAL(classToValidate, "classToValidate should not be NULL, clazz=%p\n", clazz);
6878
recordInfo->data5 = (uintptr_t)classToValidate;
6879
}
6880
6881
cg->addExternalRelocation(new (cg->trHeapMemory()) TR::BeforeBinaryEncodingExternalRelocation(firstInstruction, (uint8_t *) classSymRef, (uint8_t *) recordInfo, reloKind, cg),
6882
__FILE__, __LINE__, node);
6883
}
6884
6885
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);
6886
6887
// At this point the object is initialized and we can move it to a collected register.
6888
// The out of line path will do the same. Since the live ranges of resReg and objReg
6889
// do not overlap we want them to occupy the same real register so that this instruction
6890
// becomes a nop and can be optimized away.
6891
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, objReg, resReg);
6892
conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(1, 1, cg->trMemory());
6893
TR::addDependency(conditions, objReg, resultRealReg, TR_GPR, cg);
6894
6895
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, callReturnLabel, conditions);
6896
6897
cg->stopUsingRegister(condReg);
6898
cg->stopUsingRegister(tmp3Reg);
6899
cg->stopUsingRegister(tmp4Reg);
6900
cg->stopUsingRegister(tmp5Reg);
6901
cg->stopUsingRegister(tmp6Reg);
6902
cg->stopUsingRegister(tmp7Reg);
6903
cg->stopUsingRegister(resReg);
6904
cg->stopUsingRegister(dataSizeReg);
6905
if (!isDualTLH && needZeroInit)
6906
cg->stopUsingRegister(zeroReg);
6907
cg->decReferenceCount(firstChild);
6908
if (opCode == TR::New)
6909
{
6910
if (classReg != firstChild->getRegister())
6911
cg->stopUsingRegister(classReg);
6912
cg->stopUsingRegister(enumReg);
6913
}
6914
else
6915
{
6916
cg->decReferenceCount(secondChild);
6917
if (node->getSecondChild() != secondChild)
6918
cg->decReferenceCount(node->getSecondChild());
6919
if (classReg != secondChild->getRegister())
6920
cg->stopUsingRegister(classReg);
6921
}
6922
6923
node->setRegister(objReg);
6924
return objReg;
6925
}
6926
else
6927
{
6928
TR::Node::recreate(node, TR::acall);
6929
callResult = directCallEvaluator(node, cg);
6930
TR::Node::recreate(node, opCode);
6931
return (callResult);
6932
}
6933
}
6934
6935
// Special case evaluator for simple read monitors.
6936
static bool simpleReadMonitor(TR::Node *node, TR::CodeGenerator *cg, TR::Node *objNode, TR::Register *objReg, TR::Register *objectClassReg, TR::Register *condReg,
6937
TR::Register *lookupOffsetReg)
6938
{
6939
#if defined(J9VM_JIT_NEW_DUAL_HELPERS)
6940
// This needs to be updated to work with dual-mode helpers by not using snippets
6941
return false;
6942
#endif
6943
TR::Compilation *comp = cg->comp();
6944
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
6945
static char *disableSRM = feGetEnv("TR_disableSimpleReadMonitors");
6946
static char *nolwsync = feGetEnv("TR_noSRMlwsync");
6947
6948
if (disableSRM)
6949
return false;
6950
6951
// look for the special case of a read monitor sequence that protects
6952
// a single fixed-point load, ie:
6953
// monenter (object)
6954
// a simple form of iaload or iiload
6955
// monexit (object)
6956
6957
// note: before we make the following checks it is important that the
6958
// object on the monenter has been evaluated (currently done before the
6959
// call to this routine, and the result passed in as objReg)
6960
6961
if (!node->isReadMonitor())
6962
return false;
6963
6964
TR::TreeTop *nextTreeTop = cg->getCurrentEvaluationTreeTop()->getNextTreeTop();
6965
if (!nextTreeTop)
6966
return false;
6967
6968
TR::TreeTop *liveMonitorExitStore = NULL;
6969
TR::TreeTop *liveMonitorEnterStore = NULL;
6970
6971
if (nextTreeTop->getNode()->getOpCode().isStore() && nextTreeTop->getNode()->getSymbol()->holdsMonitoredObject())
6972
{
6973
liveMonitorEnterStore = nextTreeTop;
6974
nextTreeTop = nextTreeTop->getNextTreeTop();
6975
}
6976
6977
if (nextTreeTop->getNode()->getOpCode().getOpCodeValue() == TR::monexitfence)
6978
{
6979
liveMonitorExitStore = nextTreeTop;
6980
nextTreeTop = nextTreeTop->getNextTreeTop();
6981
}
6982
6983
TR::TreeTop *secondNextTreeTop = nextTreeTop->getNextTreeTop();
6984
if (!secondNextTreeTop)
6985
return false;
6986
6987
if (secondNextTreeTop->getNode()->getOpCode().getOpCodeValue() == TR::monexitfence)
6988
{
6989
liveMonitorExitStore = secondNextTreeTop;
6990
secondNextTreeTop = secondNextTreeTop->getNextTreeTop();
6991
}
6992
6993
// check that the second node after the monent is the matching monexit
6994
TR::Node *secondNextTopNode = secondNextTreeTop->getNode();
6995
if (!secondNextTopNode)
6996
return false;
6997
if (secondNextTopNode->getOpCodeValue() == TR::treetop)
6998
secondNextTopNode = secondNextTopNode->getFirstChild();
6999
if (secondNextTopNode->getOpCodeValue() != TR::monexit || secondNextTopNode->getFirstChild() != objNode)
7000
return false;
7001
7002
// check that the first node after the monent is a simple load
7003
TR::Node *nextTopNode = nextTreeTop->getNode();
7004
if (!nextTopNode)
7005
return false;
7006
if (nextTopNode->getOpCodeValue() == TR::treetop || nextTopNode->getOpCodeValue() == TR::iRegStore)
7007
nextTopNode = nextTopNode->getFirstChild();
7008
if (!TR::LoadStoreHandler::isSimpleLoad(cg, nextTopNode))
7009
return false;
7010
// possible TODO: expand the set of load types we can handle
7011
if (nextTopNode->getOpCodeValue() != TR::aloadi && nextTopNode->getOpCodeValue() != TR::iloadi)
7012
{
7013
// printf("Rejecting read-only monitor on load type in %s\n", comp->getCurrentMethod()->signature());
7014
return false;
7015
}
7016
// possible TODO: expand the complexity of loads we can handle
7017
// iaload and iiload are indirect and have a child
7018
// if we don't need to evaluate that child then the iaload or iiload
7019
// consists of a single hardware instruction and satisfies our current
7020
// constraint of simple
7021
if (!nextTopNode->getFirstChild()->getRegister())
7022
{
7023
// printf("Rejecting read-only monitor on complex load in %s\n", comp->getCurrentMethod()->signature());
7024
return false;
7025
}
7026
7027
// end of checks, we can handle this case
7028
// printf("Success on read-only monitor optimization in %s\n", comp->getCurrentMethod()->signature());
7029
7030
// RAS: dump out the load and monexit trees, since we are effectively
7031
// evaluating them here
7032
if (comp->getOption(TR_TraceCG) || debug("traceGRA"))
7033
{
7034
trfprintf(comp->getOutFile(), "\n");
7035
comp->getDebug()->dumpSingleTreeWithInstrs(nextTreeTop, NULL, true, false, true, comp->getOption(TR_TraceRegisterPressureDetails));
7036
trfprintf(comp->getOutFile(), "\n");
7037
comp->getDebug()->dumpSingleTreeWithInstrs(secondNextTreeTop, NULL, true, false, true, comp->getOption(TR_TraceRegisterPressureDetails));
7038
trfflush(comp->getOutFile());
7039
}
7040
7041
if (liveMonitorEnterStore)
7042
{
7043
TR::TreeTop *oldCur = cg->getCurrentEvaluationTreeTop();
7044
cg->setCurrentEvaluationTreeTop(liveMonitorEnterStore);
7045
cg->evaluate(liveMonitorEnterStore->getNode());
7046
cg->setCurrentEvaluationTreeTop(oldCur);
7047
}
7048
// check the TR::monexit to see if an lwsync is required
7049
// or whether to suppress the lwsync for performance analysis purposes
7050
bool needlwsync = comp->target().isSMP() && !secondNextTopNode->canSkipSync() && nolwsync == NULL;
7051
7052
// generate code for the combined monenter, load and monexit:
7053
// <monitor object evaluation code>
7054
// <TR_MemoryReference evaluation code for load>
7055
// (see design 908 for more information on the code sequences used)
7056
// if running on a POWER4/5 and the load is from the monitor object:
7057
// (altsequence)
7058
// if an lwsync is needed:
7059
// li offsetReg, offset_of_monitor_word
7060
// loopLabel:
7061
// lwarx monitorReg, [objReg, offsetReg]
7062
// cmpli cndReg, monitorReg, 0
7063
// bne cndReg, recurCheckLabel
7064
// stwcx [objReg, offsetReg], metaReg
7065
// bne- loopLabel
7066
// or loadBaseReg,loadBaseReg,monitorReg
7067
// <load>
7068
// lwsync
7069
// stw offsetReg(objReg), monitorReg
7070
// restartLabel:
7071
// else (no lwsync):
7072
// li offsetReg, offset_of_monitor_word
7073
// loopLabel:
7074
// lwarx monitorReg, [objReg, offsetReg]
7075
// cmpli cndReg, monitorReg, 0
7076
// bne cndReg, recurCheckLabel
7077
// stwcx [objReg, offsetReg], metaReg
7078
// bne- loopLabel
7079
// or loadBaseReg,loadBaseReg,monitorReg
7080
// <load>
7081
// xor monitorReg,loadResultReg,loadResultReg
7082
// stw offsetReg(objReg), monitorReg
7083
// restartLabel:
7084
// else:
7085
// if an lwsync is needed:
7086
// li offsetReg, offset_of_monitor_word
7087
// loopLabel:
7088
// lwarx monitorReg, [objReg, offsetReg]
7089
// cmpli cndReg, monitorReg, 0
7090
// bne cndReg, recurCheckLabel
7091
// or loadBaseReg,loadBaseReg,monitorReg
7092
// <load>
7093
// lwsync
7094
// stwcx [objReg, offsetReg], monitorReg
7095
// bne- loopLabel
7096
// restartLabel:
7097
// else (no lwsync):
7098
// li offsetReg, offset_of_monitor_word
7099
// loopLabel:
7100
// lwarx monitorReg, [objReg, offsetReg]
7101
// cmpli cndReg, monitorReg, 0
7102
// bne cndReg, recurCheckLabel
7103
// or loadBaseReg,loadBaseReg,monitorReg
7104
// <load>
7105
// xor monitorReg,loadResultReg,loadResultReg
7106
// stwcx [objReg, offsetReg], monitorReg
7107
// bne- loopLabel
7108
// restartLabel:
7109
// === SNIPPET === (generated later)
7110
// recurCheckLabel:
7111
// rlwinm monitorReg, monitorReg, 0, THREAD_MASK_CONST
7112
// cmp cndReg, metaReg, monitorReg
7113
// bne cndReg, slowPath
7114
// <load>
7115
// b restartLabel
7116
// slowPath:
7117
// bl monitorEnterHelper
7118
// <load>
7119
// bl monitorExitHelper
7120
// b restartLabel
7121
7122
TR::RegisterDependencyConditions *conditions;
7123
TR::Register *metaReg, *monitorReg, *cndReg, *offsetReg;
7124
TR::InstOpCode::Mnemonic opCode;
7125
int32_t lockSize;
7126
7127
int32_t numDeps = 6;
7128
if (objectClassReg)
7129
numDeps = numDeps + 2;
7130
7131
if (lookupOffsetReg)
7132
numDeps = numDeps + 1;
7133
7134
conditions = createConditionsAndPopulateVSXDeps(cg, numDeps);
7135
7136
monitorReg = cg->allocateRegister();
7137
offsetReg = cg->allocateRegister();
7138
cndReg = cg->allocateRegister(TR_CCR);
7139
TR::addDependency(conditions, monitorReg, TR::RealRegister::gr11, TR_GPR, cg);
7140
TR::addDependency(conditions, offsetReg, TR::RealRegister::NoReg, TR_GPR, cg);
7141
TR::addDependency(conditions, cndReg, TR::RealRegister::cr0, TR_CCR, cg);
7142
7143
// the following code is derived from the iaload and iiload evaluators
7144
TR::Register *loadResultReg;
7145
OMR::Power::NodeMemoryReference tempMR;
7146
if (nextTopNode->getOpCodeValue() == TR::aloadi)
7147
loadResultReg = cg->allocateCollectedReferenceRegister();
7148
else
7149
loadResultReg = cg->allocateRegister();
7150
if (nextTopNode->getSymbolReference()->getSymbol()->isInternalPointer())
7151
{
7152
loadResultReg->setPinningArrayPointer(nextTopNode->getSymbolReference()->getSymbol()->castToInternalPointerAutoSymbol()->getPinningArrayPointer());
7153
loadResultReg->setContainsInternalPointer();
7154
}
7155
nextTopNode->setRegister(loadResultReg);
7156
TR::InstOpCode::Mnemonic loadOpCode;
7157
if (nextTopNode->getOpCodeValue() == TR::aloadi && comp->target().is64Bit())
7158
{
7159
if (TR::Compiler->om.compressObjectReferences() && nextTopNode->getSymbol()->isClassObject())
7160
{
7161
tempMR = TR::LoadStoreHandler::generateSimpleLoadMemoryReference(cg, nextTopNode, 4);
7162
loadOpCode = TR::InstOpCode::lwz;
7163
}
7164
else
7165
{
7166
tempMR = TR::LoadStoreHandler::generateSimpleLoadMemoryReference(cg, nextTopNode, 8);
7167
loadOpCode = TR::InstOpCode::ld;
7168
}
7169
}
7170
else
7171
{
7172
tempMR = TR::LoadStoreHandler::generateSimpleLoadMemoryReference(cg, nextTopNode, 4);
7173
loadOpCode = TR::InstOpCode::lwz;
7174
}
7175
// end of code derived from the iaload and iiload evaluators
7176
7177
TR::addDependency(conditions, loadResultReg, TR::RealRegister::NoReg, TR_GPR, cg);
7178
if (tempMR.getMemoryReference()->getBaseRegister() != objReg)
7179
{
7180
TR::addDependency(conditions, tempMR.getMemoryReference()->getBaseRegister(), TR::RealRegister::NoReg, TR_GPR, cg);
7181
conditions->getPreConditions()->getRegisterDependency(4)->setExcludeGPR0();
7182
conditions->getPostConditions()->getRegisterDependency(4)->setExcludeGPR0();
7183
}
7184
TR::addDependency(conditions, objReg, TR::RealRegister::gr3, TR_GPR, cg);
7185
7186
TR::Register *baseReg = objReg;
7187
if (objectClassReg)
7188
baseReg = objectClassReg;
7189
7190
bool altsequence = (comp->target().cpu.is(OMR_PROCESSOR_PPC_GP) || comp->target().cpu.is(OMR_PROCESSOR_PPC_GR)) && tempMR.getMemoryReference()->getBaseRegister() == objReg;
7191
7192
TR::LabelSymbol *loopLabel, *restartLabel, *recurCheckLabel, *monExitCallLabel;
7193
loopLabel = generateLabelSymbol(cg);
7194
restartLabel = generateLabelSymbol(cg);
7195
recurCheckLabel = generateLabelSymbol(cg);
7196
monExitCallLabel = generateLabelSymbol(cg);
7197
7198
metaReg = cg->getMethodMetaDataRegister();
7199
7200
if (comp->target().is64Bit() && !fej9->generateCompressedLockWord())
7201
{
7202
opCode = TR::InstOpCode::ldarx;
7203
lockSize = 8;
7204
}
7205
else
7206
{
7207
opCode = TR::InstOpCode::lwarx;
7208
lockSize = 4;
7209
}
7210
7211
if (objectClassReg)
7212
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, offsetReg, 0);
7213
else
7214
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, offsetReg, fej9->getByteOffsetToLockword((TR_OpaqueClassBlock *) cg->getMonClass(node)));
7215
generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);
7216
generateTrg1MemInstruction(cg, opCode, node, monitorReg, TR::MemoryReference::createWithIndexReg(cg, baseReg, offsetReg, lockSize));
7217
generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, cndReg, monitorReg, 0);
7218
TR::Instruction *gcPoint = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, recurCheckLabel, cndReg);
7219
gcPoint->PPCNeedsGCMap(0xFFFFFFFF);
7220
7221
if (altsequence)
7222
{
7223
if (comp->target().is64Bit() && !fej9->generateCompressedLockWord())
7224
opCode = TR::InstOpCode::stdcx_r;
7225
else
7226
opCode = TR::InstOpCode::stwcx_r;
7227
generateMemSrc1Instruction(cg, opCode, node, TR::MemoryReference::createWithIndexReg(cg, baseReg, offsetReg, lockSize), metaReg);
7228
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, loopLabel, cndReg);
7229
generateTrg1Src2Instruction(cg, TR::InstOpCode::OR, node, tempMR.getMemoryReference()->getBaseRegister(), tempMR.getMemoryReference()->getBaseRegister(), monitorReg);
7230
generateTrg1MemInstruction(cg, loadOpCode, node, loadResultReg, tempMR.getMemoryReference());
7231
if (needlwsync)
7232
generateInstruction(cg, TR::InstOpCode::lwsync, node);
7233
else
7234
generateTrg1Src2Instruction(cg, TR::InstOpCode::XOR, node, monitorReg, loadResultReg, loadResultReg);
7235
if (comp->target().is64Bit() && !fej9->generateCompressedLockWord())
7236
opCode = TR::InstOpCode::std;
7237
else
7238
opCode = TR::InstOpCode::stw;
7239
generateMemSrc1Instruction(cg, opCode, node,
7240
TR::MemoryReference::createWithDisplacement(cg, baseReg, objectClassReg ? 0 : fej9->getByteOffsetToLockword((TR_OpaqueClassBlock *) cg->getMonClass(node)), lockSize), monitorReg);
7241
}
7242
else
7243
{
7244
generateTrg1Src2Instruction(cg, TR::InstOpCode::OR, node, tempMR.getMemoryReference()->getBaseRegister(), tempMR.getMemoryReference()->getBaseRegister(), monitorReg);
7245
generateTrg1MemInstruction(cg, loadOpCode, node, loadResultReg, tempMR.getMemoryReference());
7246
if (needlwsync)
7247
generateInstruction(cg, TR::InstOpCode::lwsync, node);
7248
else
7249
generateTrg1Src2Instruction(cg, TR::InstOpCode::XOR, node, monitorReg, loadResultReg, loadResultReg);
7250
if (comp->target().is64Bit() && !fej9->generateCompressedLockWord())
7251
opCode = TR::InstOpCode::stdcx_r;
7252
else
7253
opCode = TR::InstOpCode::stwcx_r;
7254
generateMemSrc1Instruction(cg, opCode, node, TR::MemoryReference::createWithIndexReg(cg, baseReg, offsetReg, lockSize), monitorReg);
7255
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, loopLabel, cndReg);
7256
}
7257
7258
if (objectClassReg)
7259
TR::addDependency(conditions, objectClassReg, TR::RealRegister::NoReg, TR_GPR, cg);
7260
7261
if (lookupOffsetReg)
7262
TR::addDependency(conditions, lookupOffsetReg, TR::RealRegister::NoReg, TR_GPR, cg);
7263
7264
if (condReg)
7265
TR::addDependency(conditions, condReg, TR::RealRegister::cr1, TR_CCR, cg);
7266
7267
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, restartLabel, conditions);
7268
7269
conditions->stopUsingDepRegs(cg, objReg, loadResultReg);
7270
cg->decReferenceCount(objNode);
7271
7272
TR::Snippet *snippet = new (cg->trHeapMemory()) TR::PPCReadMonitorSnippet(cg, node, secondNextTopNode, recurCheckLabel, monExitCallLabel, restartLabel, loadOpCode,
7273
tempMR.getMemoryReference()->getOffset(), objectClassReg);
7274
cg->addSnippet(snippet);
7275
7276
// the load and monexit trees need reference count adjustments and
7277
// must not be evaluated
7278
tempMR.decReferenceCounts(cg);
7279
cg->decReferenceCount(nextTopNode);
7280
if (secondNextTopNode == secondNextTreeTop->getNode())
7281
cg->recursivelyDecReferenceCount(secondNextTopNode->getFirstChild());
7282
else
7283
cg->recursivelyDecReferenceCount(secondNextTopNode);
7284
7285
if (liveMonitorExitStore)
7286
{
7287
TR::TreeTop *prev = liveMonitorExitStore->getPrevTreeTop();
7288
TR::TreeTop *next = liveMonitorExitStore->getNextTreeTop();
7289
prev->join(next);
7290
7291
next = secondNextTreeTop->getNextTreeTop();
7292
secondNextTreeTop->join(liveMonitorExitStore);
7293
liveMonitorExitStore->join(next);
7294
}
7295
7296
cg->setCurrentEvaluationTreeTop(secondNextTreeTop);
7297
7298
return true;
7299
}
7300
7301
void J9::Power::TreeEvaluator::generateCheckForValueMonitorEnterOrExit(TR::Node *node, TR::LabelSymbol *helperCallLabel, TR::Register *objReg, TR::Register *objectClassReg, TR::Register *temp1Reg, TR::Register *temp2Reg, TR::Register *condReg, TR::CodeGenerator *cg, int32_t classFlag)
7302
{
7303
//get class of object
7304
generateLoadJ9Class(node, objectClassReg, objReg, cg);
7305
7306
//get memory reference to class flags
7307
TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());
7308
TR::MemoryReference *classFlagsMemRef = TR::MemoryReference::createWithDisplacement(cg, objectClassReg, static_cast<uintptr_t>(fej9->getOffsetOfClassFlags()), 4);
7309
7310
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, temp1Reg, classFlagsMemRef);
7311
7312
loadConstant(cg, node, classFlag, temp2Reg);
7313
generateTrg1Src2Instruction(cg, TR::InstOpCode::and_r, node, temp1Reg, temp1Reg, temp2Reg);
7314
7315
//If obj is value type or value based class instance, call VM helper and throw IllegalMonitorState exception, else continue as usual
7316
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, helperCallLabel, condReg);
7317
}
7318
7319
TR::Register *J9::Power::TreeEvaluator::VMmonentEvaluator(TR::Node *node, TR::CodeGenerator *cg)
7320
{
7321
TR::Compilation *comp = cg->comp();
7322
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
7323
int32_t lwOffset = fej9->getByteOffsetToLockword((TR_OpaqueClassBlock *) cg->getMonClass(node));
7324
TR_ASSERT(lwOffset>=LOWER_IMMED && lwOffset<=UPPER_IMMED, "Need re-work on using lwOffset.");
7325
TR_YesNoMaybe isMonitorValueBasedOrValueType = cg->isMonitorValueBasedOrValueType(node);
7326
7327
if (comp->getOption(TR_MimicInterpreterFrameShape) ||
7328
(comp->getOption(TR_FullSpeedDebug) && node->isSyncMethodMonitor()) ||
7329
(isMonitorValueBasedOrValueType == TR_yes) ||
7330
comp->getOption(TR_DisableInlineMonEnt))
7331
{
7332
TR::ILOpCodes opCode = node->getOpCodeValue();
7333
TR::Node::recreate(node, TR::call);
7334
TR::Register *targetRegister = directCallEvaluator(node, cg);
7335
TR::Node::recreate(node, opCode);
7336
return targetRegister;
7337
}
7338
7339
int32_t numDeps = 6;
7340
7341
TR::Node *objNode = node->getFirstChild();
7342
TR::Register *objReg = cg->evaluate(objNode);
7343
7344
TR::Register *monitorReg = cg->allocateRegister();
7345
TR::Register *offsetReg = cg->allocateRegister();
7346
TR::Register *tempReg = cg->allocateRegister();
7347
7348
TR::Register *objectClassReg = cg->allocateRegister();
7349
TR::Register *lookupOffsetReg = NULL;
7350
7351
TR::Register *condReg = cg->allocateRegister(TR_CCR);
7352
TR::Register *metaReg = cg->getMethodMetaDataRegister();
7353
7354
TR::Register *baseReg = objReg;
7355
7356
if (lwOffset <= 0)
7357
{
7358
if (comp->getOption(TR_EnableMonitorCacheLookup))
7359
{
7360
lookupOffsetReg = cg->allocateRegister();
7361
numDeps++;
7362
}
7363
}
7364
7365
TR::RegisterDependencyConditions *conditions;
7366
conditions = createConditionsAndPopulateVSXDeps(cg, numDeps);
7367
7368
TR::addDependency(conditions, objReg, TR::RealRegister::NoReg, TR_GPR, cg);
7369
conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();
7370
conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();
7371
7372
TR::addDependency(conditions, monitorReg, TR::RealRegister::NoReg, TR_GPR, cg);
7373
conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();
7374
conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();
7375
7376
TR::addDependency(conditions, offsetReg, TR::RealRegister::NoReg, TR_GPR, cg);
7377
7378
TR::addDependency(conditions, tempReg, TR::RealRegister::NoReg, TR_GPR, cg);
7379
7380
TR::addDependency(conditions, objectClassReg, TR::RealRegister::NoReg, TR_GPR, cg);
7381
conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();
7382
conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();
7383
7384
if (lookupOffsetReg)
7385
{
7386
TR::addDependency(conditions, lookupOffsetReg, TR::RealRegister::NoReg, TR_GPR, cg);
7387
conditions->getPreConditions()->getRegisterDependency(conditions->getAddCursorForPre() - 1)->setExcludeGPR0();
7388
conditions->getPostConditions()->getRegisterDependency(conditions->getAddCursorForPost() - 1)->setExcludeGPR0();
7389
}
7390
7391
TR::addDependency(conditions, condReg, TR::RealRegister::cr0, TR_CCR, cg);
7392
7393
TR::LabelSymbol *callLabel = generateLabelSymbol(cg);
7394
TR::LabelSymbol *monitorLookupCacheLabel = generateLabelSymbol(cg);
7395
TR::LabelSymbol *fallThruFromMonitorLookupCacheLabel = generateLabelSymbol(cg);
7396
TR::LabelSymbol *startLabel = generateLabelSymbol(cg);
7397
7398
generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel, NULL);
7399
startLabel->setStartInternalControlFlow();
7400
7401
//If object is not known to be value type or value based class at compile time, check at run time
7402
if (isMonitorValueBasedOrValueType == TR_maybe)
7403
{
7404
generateCheckForValueMonitorEnterOrExit(node, callLabel, objReg, objectClassReg, tempReg, offsetReg, condReg, cg, J9_CLASS_DISALLOWS_LOCKING_FLAGS);
7405
}
7406
7407
bool simpleLocking = false;
7408
7409
if (lwOffset <= 0)
7410
{
7411
generateLoadJ9Class(node, objectClassReg, objReg, cg);
7412
7413
int32_t offsetOfLockOffset = offsetof(J9Class, lockOffset);
7414
TR::MemoryReference *tempMR = TR::MemoryReference::createWithDisplacement(cg, objectClassReg, offsetOfLockOffset, TR::Compiler->om.sizeofReferenceAddress());
7415
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, objectClassReg, tempMR);
7416
7417
generateTrg1Src1ImmInstruction(cg, comp->target().is64Bit() ? TR::InstOpCode::cmpi8 : TR::InstOpCode::cmpi4, node, condReg, objectClassReg, 0);
7418
7419
if (comp->getOption(TR_EnableMonitorCacheLookup))
7420
{
7421
lwOffset = 0;
7422
generateConditionalBranchInstruction(cg, TR::InstOpCode::ble, node, monitorLookupCacheLabel, condReg);
7423
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, objectClassReg, objReg, objectClassReg);
7424
generateLabelInstruction(cg, TR::InstOpCode::b, node, fallThruFromMonitorLookupCacheLabel);
7425
7426
generateLabelInstruction(cg, TR::InstOpCode::label, node, monitorLookupCacheLabel);
7427
7428
int32_t offsetOfMonitorLookupCache = offsetof(J9VMThread, objectMonitorLookupCache);
7429
7430
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, lookupOffsetReg, objReg);
7431
7432
int32_t t = trailingZeroes(TR::Compiler->om.getObjectAlignmentInBytes());
7433
7434
if (comp->target().is64Bit())
7435
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::sradi, node, lookupOffsetReg, lookupOffsetReg, t);
7436
else
7437
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::srawi, node, lookupOffsetReg, lookupOffsetReg, t);
7438
7439
J9JavaVM * jvm = fej9->getJ9JITConfig()->javaVM;
7440
if (comp->target().is64Bit())
7441
simplifyANDRegImm(node, lookupOffsetReg, lookupOffsetReg, (int64_t) J9VMTHREAD_OBJECT_MONITOR_CACHE_SIZE - 1, cg, objNode);
7442
else
7443
simplifyANDRegImm(node, lookupOffsetReg, lookupOffsetReg, J9VMTHREAD_OBJECT_MONITOR_CACHE_SIZE - 1, cg, objNode);
7444
7445
if (comp->target().is64Bit())
7446
generateShiftLeftImmediateLong(cg, node, lookupOffsetReg, lookupOffsetReg, trailingZeroes((int32_t) TR::Compiler->om.sizeofReferenceField()));
7447
else
7448
generateShiftLeftImmediate(cg, node, lookupOffsetReg, lookupOffsetReg, trailingZeroes((int32_t) TR::Compiler->om.sizeofReferenceField()));
7449
7450
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, lookupOffsetReg, lookupOffsetReg, offsetOfMonitorLookupCache);
7451
7452
generateTrg1MemInstruction(cg, (comp->target().is64Bit() && fej9->generateCompressedLockWord()) ? TR::InstOpCode::lwz :TR::InstOpCode::Op_load, node, objectClassReg,
7453
TR::MemoryReference::createWithIndexReg(cg, metaReg, lookupOffsetReg, TR::Compiler->om.sizeofReferenceField()));
7454
7455
generateTrg1Src1ImmInstruction(cg, comp->target().is64Bit() ? TR::InstOpCode::cmpi8 : TR::InstOpCode::cmpi4, node, condReg, objectClassReg, 0);
7456
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, callLabel, condReg);
7457
7458
int32_t offsetOfMonitor = offsetof(J9ObjectMonitor, monitor);
7459
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, lookupOffsetReg,
7460
TR::MemoryReference::createWithDisplacement(cg, objectClassReg, offsetOfMonitor, TR::Compiler->om.sizeofReferenceAddress()));
7461
7462
int32_t offsetOfUserData = offsetof(J9ThreadAbstractMonitor, userData);
7463
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, lookupOffsetReg,
7464
TR::MemoryReference::createWithDisplacement(cg, lookupOffsetReg, offsetOfUserData, TR::Compiler->om.sizeofReferenceAddress()));
7465
7466
generateTrg1Src2Instruction(cg, comp->target().is64Bit() ? TR::InstOpCode::cmp8 : TR::InstOpCode::cmp4, node, condReg, lookupOffsetReg, objReg);
7467
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, condReg);
7468
7469
int32_t offsetOfAlternateLockWord = offsetof(J9ObjectMonitor, alternateLockword);
7470
7471
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, objectClassReg, objectClassReg, offsetOfAlternateLockWord);
7472
7473
generateLabelInstruction(cg, TR::InstOpCode::label, node, fallThruFromMonitorLookupCacheLabel);
7474
}
7475
else
7476
{
7477
generateConditionalBranchInstruction(cg, TR::InstOpCode::ble, node, callLabel, condReg);
7478
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, objectClassReg, objReg, objectClassReg);
7479
}
7480
7481
simpleLocking = true;
7482
lwOffset = 0;
7483
baseReg = objectClassReg;
7484
}
7485
7486
/* If the -XX:-GlobalLockReservation option is set, try to use the original aggressive reserved locking code path. */
7487
if (!fej9->isEnableGlobalLockReservationSet())
7488
{
7489
bool reserveLocking = false, normalLockWithReservationPreserving = false;
7490
7491
if (!simpleLocking && comp->getOption(TR_ReservingLocks))
7492
TR::TreeEvaluator::evaluateLockForReservation(node, &reserveLocking, &normalLockWithReservationPreserving, cg);
7493
7494
if (reserveLocking)
7495
return reservationLockEnter(node, lwOffset, cg, conditions, baseReg, monitorReg, offsetReg, tempReg, condReg, callLabel);
7496
7497
if (!simpleLocking && !reserveLocking && !normalLockWithReservationPreserving && simpleReadMonitor(node, cg, objNode, objReg, objectClassReg, condReg, lookupOffsetReg))
7498
return NULL;
7499
}
7500
7501
int32_t lockSize;
7502
TR::InstOpCode::Mnemonic loadOpCode, storeOpCode, reservedLoadOpCode, conditionalStoreOpCode, compareLogicalOpCode, compareLogicalImmOpCode;
7503
7504
if (comp->target().is64Bit() && !fej9->generateCompressedLockWord())
7505
{
7506
lockSize = 8;
7507
loadOpCode = TR::InstOpCode::ld;
7508
storeOpCode = TR::InstOpCode::std;
7509
reservedLoadOpCode = TR::InstOpCode::ldarx;
7510
conditionalStoreOpCode = TR::InstOpCode::stdcx_r;
7511
compareLogicalOpCode = TR::InstOpCode::cmpl8;
7512
compareLogicalImmOpCode = TR::InstOpCode::cmpli8;
7513
}
7514
else
7515
{
7516
lockSize = 4;
7517
loadOpCode = TR::InstOpCode::lwz;
7518
storeOpCode = TR::InstOpCode::stw;
7519
reservedLoadOpCode = TR::InstOpCode::lwarx;
7520
conditionalStoreOpCode = TR::InstOpCode::stwcx_r;
7521
compareLogicalOpCode = TR::InstOpCode::cmpl4;
7522
compareLogicalImmOpCode = TR::InstOpCode::cmpli4;
7523
}
7524
7525
// full codegen support for read monitors is not enabled, pending performance tuning
7526
/*
7527
* Read only locks do not support either the Reserved bit nor the Learning bit.
7528
* They are disabled until the code path is updated.
7529
*/
7530
if (true || !ppcSupportsReadMonitors || !node->isReadMonitor())
7531
{
7532
/*
7533
* JIT locking fast path checks:
7534
* 1. Compare lockword to 0. If equal, use CAS to set TID in lockword.
7535
* 2. Check if TID matches, highest RC bit is 0, Learning bit is clear and Inflated bit is clear. If so, increment RC.
7536
* 3. All fast path checks failed so go to VM.
7537
*
7538
* Check 1 catches Flat-Unlocked.
7539
* Check 2 catches Reserved-Unlocked, Reserved-Locked and Flat-Locked.
7540
* Check 3 catches New-PreLearning, New-AutoReserve, Learning-Unlocked, Learning-Locked and Inflated and sends them to the VM.
7541
*
7542
*
7543
* ld/lwz monitorReg, lwOffset(baseReg)
7544
* cmpli cr0, monitorReg, 0
7545
* bne incrementCheckLabel
7546
* li offsetReg, lwOffset
7547
*
7548
* loopLabel:
7549
* larx monitorReg, [baseReg, offsetReg]
7550
* cmpli cr0, monitorReg, 0
7551
* bne callLabel
7552
* stcx. metaReg, [baseReg, offsetReg]
7553
* bne loopLabel
7554
* isync
7555
* b doneLabel
7556
*
7557
* incrementCheckLabel:
7558
* li tempReg, LOCK_NON_PRIMITIVE_ENTER_IGNORE_MASK
7559
* andc tempReg, monitorReg, tempReg
7560
* cmpl cr0, tempReg, metaReg
7561
* bne callLabel
7562
* addi monitorReg, monitorReg, LOCK_INC_DEC_VALUE
7563
* st monitorReg, lwOffset(baseReg)
7564
*
7565
* doneLabel:
7566
* callReturnLabel:
7567
* === OUT OF LINE ===
7568
* callLabel:
7569
* bl jitMonitorEntry
7570
* b callReturnLabel
7571
*/
7572
7573
TR::LabelSymbol *loopLabel, *incrementCheckLabel, *doneLabel;
7574
loopLabel = generateLabelSymbol(cg);
7575
incrementCheckLabel = generateLabelSymbol(cg);
7576
doneLabel = generateLabelSymbol(cg);
7577
7578
generateTrg1MemInstruction(cg, loadOpCode, node, monitorReg, TR::MemoryReference::createWithDisplacement(cg, baseReg, lwOffset, lockSize));
7579
7580
generateTrg1Src1ImmInstruction(cg, compareLogicalImmOpCode, node, condReg, monitorReg, 0);
7581
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, incrementCheckLabel, condReg);
7582
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, offsetReg, lwOffset);
7583
7584
generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);
7585
generateTrg1MemInstruction(cg, reservedLoadOpCode, PPCOpProp_LoadReserveExclusiveAccess, node, monitorReg, TR::MemoryReference::createWithIndexReg(cg, baseReg, offsetReg, lockSize));
7586
generateTrg1Src1ImmInstruction(cg, compareLogicalImmOpCode, node, condReg, monitorReg, 0);
7587
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, condReg);
7588
generateMemSrc1Instruction(cg, conditionalStoreOpCode, node, TR::MemoryReference::createWithIndexReg(cg, baseReg, offsetReg, lockSize), metaReg);
7589
7590
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, loopLabel, condReg);
7591
7592
if (comp->target().isSMP())
7593
{
7594
// either an isync or a sync can be used here to prevent any
7595
// following loads from executing out-of-order
7596
// on nstar and pulsar a sync is cheaper, while an isync is
7597
// cheaper on other processors
7598
if (comp->target().cpu.is(OMR_PROCESSOR_PPC_NSTAR) || comp->target().cpu.is(OMR_PROCESSOR_PPC_PULSAR))
7599
generateInstruction(cg, TR::InstOpCode::sync, node);
7600
else
7601
generateInstruction(cg, TR::InstOpCode::isync, node);
7602
}
7603
generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);
7604
7605
generateLabelInstruction(cg, TR::InstOpCode::label, node, incrementCheckLabel);
7606
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tempReg, LOCK_NON_PRIMITIVE_ENTER_IGNORE_MASK);
7607
generateTrg1Src2Instruction(cg, TR::InstOpCode::andc, node, tempReg, monitorReg, tempReg);
7608
generateTrg1Src2Instruction(cg, compareLogicalOpCode, node, condReg, tempReg, metaReg);
7609
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, condReg);
7610
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, monitorReg, monitorReg, LOCK_INC_DEC_VALUE);
7611
generateMemSrc1Instruction(cg, storeOpCode, node, TR::MemoryReference::createWithDisplacement(cg, baseReg, lwOffset, lockSize), monitorReg);
7612
7613
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);
7614
7615
doneLabel->setEndInternalControlFlow();
7616
7617
TR::LabelSymbol *callReturnLabel = generateLabelSymbol(cg);
7618
7619
TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::call, NULL, callLabel, callReturnLabel, cg);
7620
cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);
7621
7622
generateLabelInstruction(cg, TR::InstOpCode::label, node, callReturnLabel);
7623
7624
conditions->stopUsingDepRegs(cg, objReg);
7625
cg->decReferenceCount(objNode);
7626
}
7627
else
7628
{
7629
// read-only locks, readerReg = 0x0000 0000
7630
// li offsetReg, offset_of_monitor_word
7631
// loopLabel:
7632
// larx monitorReg, [baseReg, offsetReg]
7633
// rlwinm tempReg, monitorReg, 0, 0xFFFFFF83
7634
// cmpi cr0, tempReg, 0x0
7635
// bne callLabel
7636
// addi monitorReg, monitorReg, 4
7637
// stcx. [baseReg, offsetReg], monitorReg
7638
// bne loopLabel
7639
// isync
7640
// doneLabel:
7641
// callReturnLabel:
7642
// === OUT OF LINE ===
7643
// callLabel:
7644
// bl jitMonitorEntry
7645
// b callReturnLabel
7646
7647
TR::LabelSymbol *doneLabel, *loopLabel;
7648
doneLabel = generateLabelSymbol(cg);
7649
loopLabel = generateLabelSymbol(cg);
7650
7651
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, offsetReg, lwOffset);
7652
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel, conditions);
7653
generateTrg1MemInstruction(cg, reservedLoadOpCode, PPCOpProp_LoadReserveExclusiveAccess, node, monitorReg,
7654
TR::MemoryReference::createWithIndexReg(cg, baseReg, offsetReg, lockSize));
7655
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, tempReg, monitorReg, 0, 0xFFFFFF80);
7656
generateTrg1Src1ImmInstruction(cg, compareLogicalImmOpCode, node, condReg, tempReg, 0);
7657
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, callLabel, condReg);
7658
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, monitorReg, monitorReg, 4);
7659
generateMemSrc1Instruction(cg, conditionalStoreOpCode, node, TR::MemoryReference::createWithIndexReg(cg, baseReg, offsetReg, lockSize), monitorReg);
7660
7661
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, loopLabel, condReg);
7662
7663
if (comp->target().isSMP())
7664
{
7665
// either an isync or a sync can be used here to prevent any
7666
// following loads from executing out-of-order
7667
// on nstar and pulsar a sync is cheaper, while an isync is
7668
// cheaper on other processors
7669
if (comp->target().cpu.is(OMR_PROCESSOR_PPC_NSTAR) || comp->target().cpu.is(OMR_PROCESSOR_PPC_PULSAR))
7670
generateInstruction(cg, TR::InstOpCode::sync, node);
7671
else
7672
generateInstruction(cg, TR::InstOpCode::isync, node);
7673
}
7674
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);
7675
7676
doneLabel->setEndInternalControlFlow();
7677
7678
TR::LabelSymbol *callReturnLabel = generateLabelSymbol(cg);
7679
7680
TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::call, NULL, callLabel, callReturnLabel, cg);
7681
cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);
7682
7683
generateLabelInstruction(cg, TR::InstOpCode::label, node, callReturnLabel);
7684
7685
conditions->stopUsingDepRegs(cg, objReg);
7686
cg->decReferenceCount(objNode);
7687
}
7688
7689
return (NULL);
7690
}
7691
7692
TR::Register *J9::Power::TreeEvaluator::VMarrayCheckEvaluator(TR::Node *node, TR::CodeGenerator *cg)
7693
{
7694
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
7695
TR::Register *obj1Reg, *obj2Reg, *tmp1Reg, *tmp2Reg, *cndReg;
7696
TR::LabelSymbol *doneLabel, *snippetLabel;
7697
TR::Instruction *gcPoint;
7698
TR::Snippet *snippet;
7699
TR::RegisterDependencyConditions *conditions;
7700
int32_t depIndex;
7701
TR::Compilation* comp = cg->comp();
7702
7703
obj1Reg = cg->evaluate(node->getFirstChild());
7704
obj2Reg = cg->evaluate(node->getSecondChild());
7705
doneLabel = generateLabelSymbol(cg);
7706
conditions = createConditionsAndPopulateVSXDeps(cg, 5);
7707
depIndex = 0;
7708
nonFixedDependency(conditions, obj1Reg, &depIndex, TR_GPR, true, cg);
7709
nonFixedDependency(conditions, obj2Reg, &depIndex, TR_GPR, true, cg);
7710
tmp1Reg = nonFixedDependency(conditions, NULL, &depIndex, TR_GPR, true, cg);
7711
tmp2Reg = nonFixedDependency(conditions, NULL, &depIndex, TR_GPR, false, cg);
7712
cndReg = cg->allocateRegister(TR_CCR);
7713
TR::addDependency(conditions, cndReg, TR::RealRegister::cr0, TR_CCR, cg);
7714
7715
// We have a unique snippet sharing arrangement in this code sequence.
7716
// It is not generally applicable for other situations.
7717
snippetLabel = NULL;
7718
7719
// Same array, we are done.
7720
//
7721
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, obj1Reg, obj2Reg);
7722
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, cndReg);
7723
7724
// If we know nothing about either object, test object1 first. It has to be an array.
7725
//
7726
if (!node->isArrayChkPrimitiveArray1() && !node->isArrayChkReferenceArray1() && !node->isArrayChkPrimitiveArray2() && !node->isArrayChkReferenceArray2())
7727
{
7728
7729
generateLoadJ9Class(node, tmp1Reg, obj1Reg, cg);
7730
7731
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, tmp1Reg, TR::MemoryReference::createWithDisplacement(cg, tmp1Reg, (int32_t) offsetof(J9Class, classDepthAndFlags), 4));
7732
7733
loadConstant(cg, node, (int32_t) J9AccClassRAMArray, tmp2Reg);
7734
generateTrg1Src2Instruction(cg, TR::InstOpCode::AND, node, tmp2Reg, tmp1Reg, tmp2Reg);
7735
7736
generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpi, node, cndReg, tmp2Reg, NULLVALUE);
7737
7738
snippetLabel = generateLabelSymbol(cg);
7739
gcPoint = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, snippetLabel, cndReg);
7740
snippet = new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference(), doneLabel);
7741
cg->addSnippet(snippet);
7742
}
7743
7744
// One of the object is array. Test equality of two objects' classes.
7745
//
7746
generateLoadJ9Class(node, tmp2Reg, obj2Reg, cg);
7747
generateLoadJ9Class(node, tmp1Reg, obj1Reg, cg);
7748
7749
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, cndReg, tmp1Reg, tmp2Reg);
7750
7751
// If either object is known to be of primitive component type,
7752
// we are done: since both of them have to be of equal class.
7753
if (node->isArrayChkPrimitiveArray1() || node->isArrayChkPrimitiveArray2())
7754
{
7755
if (snippetLabel == NULL)
7756
{
7757
snippetLabel = generateLabelSymbol(cg);
7758
gcPoint = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, snippetLabel, cndReg);
7759
snippet = new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference(), doneLabel);
7760
cg->addSnippet(snippet);
7761
}
7762
else
7763
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, snippetLabel, cndReg);
7764
}
7765
// We have to take care of the un-equal class situation: both of them must be of reference array
7766
else
7767
{
7768
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, cndReg);
7769
7770
// Object1 must be of reference component type, otherwise throw exception
7771
if (!node->isArrayChkReferenceArray1())
7772
{
7773
7774
// Loading the Class Pointer -> classDepthAndFlags
7775
generateLoadJ9Class(node, tmp1Reg, obj1Reg, cg);
7776
7777
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, tmp1Reg, TR::MemoryReference::createWithDisplacement(cg, tmp1Reg, (int32_t) offsetof(J9Class, classDepthAndFlags), 4));
7778
7779
// We already have classDepth&Flags in tmp1Reg. X = (ramclass->ClassDepthAndFlags)>>J9AccClassRAMShapeShift
7780
generateShiftRightLogicalImmediate(cg, node, tmp1Reg, tmp1Reg, J9AccClassRAMShapeShift);
7781
7782
// We need to perform a X & OBJECT_HEADER_SHAPE_MASK
7783
7784
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, tmp2Reg, tmp1Reg, 0, OBJECT_HEADER_SHAPE_MASK);
7785
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, cndReg, tmp2Reg, OBJECT_HEADER_SHAPE_POINTERS);
7786
7787
if (snippetLabel == NULL)
7788
{
7789
snippetLabel = generateLabelSymbol(cg);
7790
gcPoint = generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, snippetLabel, cndReg);
7791
snippet = new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference(), doneLabel);
7792
cg->addSnippet(snippet);
7793
}
7794
else
7795
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, snippetLabel, cndReg);
7796
}
7797
7798
// Object2 must be of reference component type array, otherwise throw exception
7799
if (!node->isArrayChkReferenceArray2())
7800
{
7801
7802
generateLoadJ9Class(node, tmp1Reg, obj2Reg, cg);
7803
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, tmp1Reg, TR::MemoryReference::createWithDisplacement(cg, tmp1Reg, (int32_t) offsetof(J9Class, classDepthAndFlags), 4));
7804
7805
loadConstant(cg, node, (int32_t) J9AccClassRAMArray, tmp2Reg);
7806
generateTrg1Src2Instruction(cg, TR::InstOpCode::AND, node, tmp2Reg, tmp1Reg, tmp2Reg);
7807
7808
TR::Instruction * i = generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpi, node, cndReg, tmp2Reg, NULLVALUE);
7809
7810
if (snippetLabel == NULL)
7811
{
7812
snippetLabel = generateLabelSymbol(cg);
7813
gcPoint = generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, snippetLabel, cndReg);
7814
snippet = new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, snippetLabel, node->getSymbolReference(), doneLabel);
7815
cg->addSnippet(snippet);
7816
}
7817
else
7818
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, snippetLabel, cndReg);
7819
7820
// We already have classDepth&Flags in tmp1Reg. X = (ramclass->ClassDepthAndFlags)>>J9AccClassRAMShapeShift
7821
generateShiftRightLogicalImmediate(cg, node, tmp1Reg, tmp1Reg, J9AccClassRAMShapeShift);
7822
7823
// We need to perform a X & OBJECT_HEADER_SHAPE_MASK
7824
7825
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, tmp2Reg, tmp1Reg, 0, OBJECT_HEADER_SHAPE_MASK);
7826
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, cndReg, tmp2Reg, OBJECT_HEADER_SHAPE_POINTERS);
7827
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, snippetLabel, cndReg);
7828
}
7829
}
7830
7831
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);
7832
if (snippetLabel != NULL)
7833
{
7834
gcPoint->PPCNeedsGCMap(0x0);
7835
snippet->gcMap().setGCRegisterMask(0x0);
7836
}
7837
7838
conditions->stopUsingDepRegs(cg, obj1Reg, obj2Reg);
7839
7840
cg->decReferenceCount(node->getFirstChild());
7841
cg->decReferenceCount(node->getSecondChild());
7842
return (NULL);
7843
}
7844
7845
void J9::Power::TreeEvaluator::genArrayCopyWithArrayStoreCHK(TR::Node* node, TR::CodeGenerator *cg)
7846
{
7847
TR::Compilation *comp = cg->comp();
7848
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
7849
TR::Register *metaReg = cg->getMethodMetaDataRegister();
7850
TR::Register *gr3Reg, *gr2Reg, *lengthReg, *temp1Reg;
7851
7852
// child 0 ------ Source array object;
7853
// child 1 ------ Destination array object;
7854
// child 2 ------ Source byte address;
7855
// child 3 ------ Destination byte address;
7856
// child 4 ------ Copy length in byte;
7857
7858
bool aix_style_linkage = (comp->target().isAIX() || (comp->target().is64Bit() && comp->target().isLinux()));
7859
J9::Power::JNILinkage *jniLinkage = (J9::Power::JNILinkage*) cg->getLinkage(TR_J9JNILinkage);
7860
const TR::PPCLinkageProperties &pp = jniLinkage->getProperties();
7861
TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(pp.getNumberOfDependencyGPRegisters(),
7862
pp.getNumberOfDependencyGPRegisters(), cg->trMemory());
7863
7864
// I_32 referenceArrayCopy(
7865
// J9VMThread *vmThread,
7866
// J9IndexableObjectContiguous *srcObject,
7867
// J9IndexableObjectContiguous *destObject,
7868
// U_8 *srcAddress,
7869
// U_8 *destAddress,
7870
// I_32 lengthInSlots)
7871
intptr_t *funcdescrptr = (intptr_t*) fej9->getReferenceArrayCopyHelperAddress();
7872
7873
TR::Instruction *iCursor;
7874
if (aix_style_linkage)
7875
{
7876
gr2Reg = cg->allocateRegister();
7877
TR::addDependency(conditions, gr2Reg, TR::RealRegister::gr2, TR_GPR, cg);
7878
}
7879
// set up the arguments and dependencies
7880
int32_t argSize = jniLinkage->buildJNIArgs(node, conditions, pp, true);
7881
temp1Reg = conditions->searchPreConditionRegister(TR::RealRegister::gr12);
7882
if (aix_style_linkage &&
7883
!(comp->target().is64Bit() && comp->target().isLinux() && comp->target().cpu.isLittleEndian()))
7884
{
7885
intptr_t target_ip = funcdescrptr[0];
7886
intptr_t target_toc = funcdescrptr[1];
7887
iCursor = loadAddressConstant(cg, comp->compileRelocatableCode(), node, target_ip, temp1Reg, NULL, false, TR_ArrayCopyHelper);
7888
iCursor = loadAddressConstant(cg, comp->compileRelocatableCode(), node, target_toc, gr2Reg, iCursor, false, TR_ArrayCopyToc);
7889
}
7890
else
7891
{
7892
bool doRelocation = comp->compileRelocatableCode();
7893
#ifdef J9VM_OPT_JITSERVER
7894
doRelocation = doRelocation || comp->isOutOfProcessCompilation();
7895
#endif
7896
iCursor = loadAddressConstant(cg, doRelocation, node, (intptr_t) funcdescrptr, temp1Reg, NULL, false, TR_ArrayCopyHelper);
7897
}
7898
7899
iCursor = generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, temp1Reg, NULL, iCursor);
7900
// the C routine expects length measured by slots
7901
lengthReg = conditions->searchPreConditionRegister(TR::RealRegister::gr8);
7902
int32_t elementSize;
7903
if (comp->useCompressedPointers())
7904
elementSize = TR::Compiler->om.sizeofReferenceField();
7905
else
7906
elementSize = (int32_t) TR::Compiler->om.sizeofReferenceAddress();
7907
generateShiftRightLogicalImmediate(cg, node, lengthReg, lengthReg, trailingZeroes(elementSize));
7908
// pass vmThread as the first parameter
7909
gr3Reg = cg->allocateRegister();
7910
TR::addDependency(conditions, gr3Reg, TR::RealRegister::gr3, TR_GPR, cg);
7911
iCursor = generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, gr3Reg, metaReg, iCursor);
7912
// call the C routine
7913
TR::Instruction *gcPoint = generateDepInstruction(cg, TR::InstOpCode::bctrl, node, conditions);
7914
gcPoint->PPCNeedsGCMap(pp.getPreservedRegisterMapForGC());
7915
// check return value
7916
TR::Register *cr0Reg = conditions->searchPreConditionRegister(TR::RealRegister::cr0);
7917
generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpi, node, cr0Reg, gr3Reg, -1);
7918
// throw exception if needed
7919
TR::SymbolReference *throwSymRef = comp->getSymRefTab()->findOrCreateArrayStoreExceptionSymbolRef(comp->getJittedMethodSymbol());
7920
TR::LabelSymbol *exceptionSnippetLabel = cg->lookUpSnippet(TR::Snippet::IsHelperCall, throwSymRef);
7921
if (exceptionSnippetLabel == NULL)
7922
{
7923
exceptionSnippetLabel = generateLabelSymbol(cg);
7924
cg->addSnippet(new (cg->trHeapMemory()) TR::PPCHelperCallSnippet(cg, node, exceptionSnippetLabel, throwSymRef));
7925
}
7926
7927
gcPoint = generateDepConditionalBranchInstruction(cg, TR::InstOpCode::bnel, node, exceptionSnippetLabel, cr0Reg, conditions->cloneAndFix(cg));
7928
// somewhere to hang the dependencies
7929
TR::LabelSymbol *depLabel = generateLabelSymbol(cg);
7930
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, depLabel, conditions);
7931
gcPoint->PPCNeedsGCMap(pp.getPreservedRegisterMapForGC());
7932
cg->machine()->setLinkRegisterKilled(true);
7933
conditions->stopUsingDepRegs(cg);
7934
cg->setHasCall();
7935
return;
7936
}
7937
7938
void J9::Power::TreeEvaluator::genWrtbarForArrayCopy(TR::Node *node, TR::Register *srcObjReg, TR::Register *dstObjReg, TR::CodeGenerator *cg)
7939
{
7940
TR::Compilation *comp = cg->comp();
7941
bool ageCheckIsNeeded = false;
7942
bool cardMarkIsNeeded = false;
7943
auto gcMode = TR::Compiler->om.writeBarrierType();
7944
TR::RegisterDependencyConditions *conditions = NULL;
7945
7946
ageCheckIsNeeded = (gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always);
7947
cardMarkIsNeeded = (gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_incremental);
7948
7949
if (!ageCheckIsNeeded && !cardMarkIsNeeded)
7950
return;
7951
7952
if (ageCheckIsNeeded)
7953
{
7954
TR::Register *temp1Reg;
7955
TR::Register *temp2Reg;
7956
TR::Register *condReg = cg->allocateRegister(TR_CCR);
7957
TR::Instruction *gcPoint;
7958
7959
if (gcMode != gc_modron_wrtbar_always)
7960
{
7961
temp1Reg = cg->allocateRegister();
7962
temp2Reg = cg->allocateRegister();
7963
conditions = createConditionsAndPopulateVSXDeps(cg, 4);
7964
TR::addDependency(conditions, temp1Reg, TR::RealRegister::gr11, TR_GPR, cg);
7965
TR::addDependency(conditions, temp2Reg, TR::RealRegister::NoReg, TR_GPR, cg);
7966
}
7967
else
7968
{
7969
conditions = createConditionsAndPopulateVSXDeps(cg, 2);
7970
}
7971
7972
TR::addDependency(conditions, dstObjReg, TR::RealRegister::gr3, TR_GPR, cg);
7973
TR::addDependency(conditions, condReg, TR::RealRegister::cr0, TR_CCR, cg);
7974
7975
TR::LabelSymbol *doneLabel;
7976
TR::SymbolReference *wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierBatchStoreSymbolRef(comp->getMethodSymbol());
7977
7978
if (gcMode != gc_modron_wrtbar_always)
7979
{
7980
doneLabel = generateLabelSymbol(cg);
7981
7982
TR::Register *metaReg = cg->getMethodMetaDataRegister();
7983
7984
// temp1Reg = dstObjReg - heapBaseForBarrierRange0
7985
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp1Reg,
7986
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapBaseForBarrierRange0), TR::Compiler->om.sizeofReferenceAddress()));
7987
generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, temp1Reg, temp1Reg, dstObjReg);
7988
7989
// if (temp1Reg >= heapSizeForBarrierRage0), object not in the tenured area
7990
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, temp2Reg,
7991
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, heapSizeForBarrierRange0), TR::Compiler->om.sizeofReferenceAddress()));
7992
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, temp1Reg, temp2Reg);
7993
generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, doneLabel, condReg);
7994
}
7995
7996
gcPoint = generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t) wbRef->getSymbol()->castToMethodSymbol()->getMethodAddress(),
7997
new (cg->trHeapMemory()) TR::RegisterDependencyConditions((uint8_t) 0, 0, cg->trMemory()), wbRef, NULL);
7998
7999
if (gcMode != gc_modron_wrtbar_always)
8000
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);
8001
8002
cg->machine()->setLinkRegisterKilled(true);
8003
cg->setHasCall();
8004
8005
// This GC point can only happen when there is an exception. As a result, we can ditch
8006
// all registers.
8007
gcPoint->PPCNeedsGCMap(0xFFFFFFFF);
8008
}
8009
8010
if (!ageCheckIsNeeded && cardMarkIsNeeded)
8011
{
8012
if (!comp->getOptions()->realTimeGC())
8013
8014
{
8015
TR::Register *cndReg = cg->allocateRegister(TR_CCR);
8016
TR::Register *temp1Reg = cg->allocateRegister();
8017
TR::Register *temp2Reg = cg->allocateRegister();
8018
TR::Register *temp3Reg = cg->allocateRegister();
8019
conditions = createConditionsAndPopulateVSXDeps(cg, 7);
8020
8021
TR::addDependency(conditions, cndReg, TR::RealRegister::cr0, TR_CCR, cg);
8022
TR::addDependency(conditions, dstObjReg, TR::RealRegister::NoReg, TR_GPR, cg);
8023
TR::addDependency(conditions, temp1Reg, TR::RealRegister::NoReg, TR_GPR, cg);
8024
conditions->getPostConditions()->getRegisterDependency(1)->setExcludeGPR0();
8025
conditions->getPostConditions()->getRegisterDependency(2)->setExcludeGPR0();
8026
TR::addDependency(conditions, temp2Reg, TR::RealRegister::NoReg, TR_GPR, cg);
8027
TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);
8028
8029
VMCardCheckEvaluator(node, dstObjReg, cndReg, temp1Reg, temp2Reg, temp3Reg, conditions, cg);
8030
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, generateLabelSymbol(cg), conditions);
8031
8032
}
8033
else
8034
TR_ASSERT(0, "genWrtbarForArrayCopy card marking not supported for RT");
8035
}
8036
if (conditions)
8037
{
8038
conditions->stopUsingDepRegs(cg, dstObjReg);
8039
}
8040
}
8041
8042
static TR::Register *genCAS(TR::Node *node, TR::CodeGenerator *cg, TR::Register *objReg, TR::Register *offsetReg, TR::Register *oldVReg, TR::Register *newVReg, TR::Register *cndReg,
8043
TR::LabelSymbol *doneLabel, TR::Node *objNode, int32_t oldValue, bool oldValueInReg, bool isLong, bool casWithoutSync = false)
8044
{
8045
TR::Register *resultReg = cg->allocateRegister();
8046
TR::Instruction *gcPoint;
8047
8048
// Memory barrier --- NOTE: we should be able to do a test upfront to save this barrier,
8049
// but Hursley advised to be conservative due to lack of specification.
8050
generateInstruction(cg, TR::InstOpCode::lwsync, node);
8051
8052
TR::LabelSymbol *loopLabel = generateLabelSymbol(cg);
8053
generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);
8054
8055
generateTrg1MemInstruction(cg, isLong ? TR::InstOpCode::ldarx : TR::InstOpCode::lwarx, node, resultReg, TR::MemoryReference::createWithIndexReg(cg, objReg, offsetReg, isLong ? 8 : 4));
8056
if (oldValueInReg)
8057
generateTrg1Src2Instruction(cg, isLong ? TR::InstOpCode::cmp8 : TR::InstOpCode::cmp4, node, cndReg, resultReg, oldVReg);
8058
else
8059
generateTrg1Src1ImmInstruction(cg, isLong ? TR::InstOpCode::cmpi8 : TR::InstOpCode::cmpi4, node, cndReg, resultReg, oldValue);
8060
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 0);
8061
8062
// We don't know how the compare will fare such that we don't dictate the prediction
8063
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, doneLabel, cndReg);
8064
8065
generateMemSrc1Instruction(cg, isLong ? TR::InstOpCode::stdcx_r : TR::InstOpCode::stwcx_r, node, TR::MemoryReference::createWithIndexReg(cg, objReg, offsetReg, isLong ? 8 : 4), newVReg);
8066
// We expect this store is usually successful, i.e., the following branch will not be taken
8067
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, loopLabel, cndReg);
8068
8069
// We deviate from the VM helper here: no-store-no-barrier instead of always-barrier
8070
if (!casWithoutSync)
8071
generateInstruction(cg, TR::InstOpCode::sync, node);
8072
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1);
8073
8074
node->setRegister(resultReg);
8075
return resultReg;
8076
}
8077
8078
static TR::Register *VMinlineCompareAndSwap(TR::Node *node, TR::CodeGenerator *cg, bool isLong)
8079
{
8080
TR::Compilation * comp = cg->comp();
8081
TR::Register *objReg, *offsetReg, *oldVReg, *newVReg, *resultReg, *cndReg;
8082
TR::Node *firstChild, *secondChild, *thirdChild, *fourthChild, *fifthChild;
8083
TR::RegisterDependencyConditions *conditions;
8084
TR::LabelSymbol *doneLabel;
8085
intptr_t offsetValue, oldValue;
8086
bool oldValueInReg = true, freeOffsetReg = false;
8087
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->fe());
8088
8089
firstChild = node->getFirstChild();
8090
secondChild = node->getSecondChild();
8091
thirdChild = node->getChild(2);
8092
fourthChild = node->getChild(3);
8093
fifthChild = node->getChild(4);
8094
objReg = cg->evaluate(secondChild);
8095
8096
// VM helper chops off the value in 32bit, and we don't want the whole long value either
8097
if (thirdChild->getOpCode().isLoadConst() && thirdChild->getRegister() == NULL && comp->target().is32Bit())
8098
{
8099
offsetValue = thirdChild->getLongInt();
8100
offsetReg = cg->allocateRegister();
8101
loadConstant(cg, node, (int32_t) offsetValue, offsetReg);
8102
freeOffsetReg = true;
8103
}
8104
else
8105
{
8106
offsetReg = cg->evaluate(thirdChild);
8107
if (comp->target().is32Bit())
8108
offsetReg = offsetReg->getLowOrder();
8109
}
8110
8111
if (fourthChild->getOpCode().isLoadConst() && fourthChild->getRegister() == NULL)
8112
{
8113
if (isLong)
8114
oldValue = fourthChild->getLongInt();
8115
else
8116
oldValue = fourthChild->getInt();
8117
if (oldValue >= LOWER_IMMED && oldValue <= UPPER_IMMED)
8118
oldValueInReg = false;
8119
}
8120
if (oldValueInReg)
8121
oldVReg = cg->evaluate(fourthChild);
8122
newVReg = cg->evaluate(fifthChild);
8123
cndReg = cg->allocateRegister(TR_CCR);
8124
doneLabel = generateLabelSymbol(cg);
8125
8126
bool casWithoutSync = false;
8127
TR_OpaqueMethodBlock *caller = node->getOwningMethod();
8128
if (caller)
8129
{
8130
TR_ResolvedMethod *m = fej9->createResolvedMethod(cg->trMemory(), caller, node->getSymbolReference()->getOwningMethod(comp));
8131
if ((m->getRecognizedMethod() == TR::java_util_concurrent_atomic_AtomicInteger_weakCompareAndSet)
8132
|| (m->getRecognizedMethod() == TR::java_util_concurrent_atomic_AtomicLong_weakCompareAndSet)
8133
|| (m->getRecognizedMethod() == TR::java_util_concurrent_atomic_AtomicReference_weakCompareAndSet))
8134
{
8135
casWithoutSync = true;
8136
}
8137
}
8138
8139
resultReg = genCAS(node, cg, objReg, offsetReg, oldVReg, newVReg, cndReg, doneLabel, secondChild, oldValue, oldValueInReg, isLong, casWithoutSync);
8140
8141
conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(6, 6, cg->trMemory());
8142
TR::addDependency(conditions, objReg, TR::RealRegister::NoReg, TR_GPR, cg);
8143
conditions->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0();
8144
TR::addDependency(conditions, offsetReg, TR::RealRegister::NoReg, TR_GPR, cg);
8145
TR::addDependency(conditions, resultReg, TR::RealRegister::NoReg, TR_GPR, cg);
8146
TR::addDependency(conditions, newVReg, TR::RealRegister::NoReg, TR_GPR, cg);
8147
if (oldValueInReg)
8148
TR::addDependency(conditions, oldVReg, TR::RealRegister::NoReg, TR_GPR, cg);
8149
TR::addDependency(conditions, cndReg, TR::RealRegister::cr0, TR_CCR, cg);
8150
8151
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);
8152
8153
cg->stopUsingRegister(cndReg);
8154
cg->recursivelyDecReferenceCount(firstChild);
8155
cg->decReferenceCount(secondChild);
8156
if (freeOffsetReg)
8157
{
8158
cg->stopUsingRegister(offsetReg);
8159
cg->recursivelyDecReferenceCount(thirdChild);
8160
}
8161
else
8162
cg->decReferenceCount(thirdChild);
8163
if (oldValueInReg)
8164
cg->decReferenceCount(fourthChild);
8165
else
8166
cg->recursivelyDecReferenceCount(fourthChild);
8167
cg->decReferenceCount(fifthChild);
8168
return resultReg;
8169
}
8170
8171
static TR::Register *VMinlineCompareAndSwapObject(TR::Node *node, TR::CodeGenerator *cg)
8172
{
8173
TR::Compilation *comp = cg->comp();
8174
TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());
8175
TR::Register *objReg, *offsetReg, *oldVReg, *newVReg, *resultReg, *cndReg;
8176
TR::Node *firstChild, *secondChild, *thirdChild, *fourthChild, *fifthChild;
8177
TR::RegisterDependencyConditions *conditions;
8178
TR::LabelSymbol *doneLabel, *storeLabel, *wrtBarEndLabel;
8179
intptr_t offsetValue;
8180
bool freeOffsetReg = false;
8181
bool needDup = false;
8182
8183
auto gcMode = TR::Compiler->om.writeBarrierType();
8184
bool doWrtBar = (gcMode == gc_modron_wrtbar_satb || gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always
8185
|| comp->getOptions()->realTimeGC());
8186
bool doCrdMrk = (gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_cardmark_incremental);
8187
8188
firstChild = node->getFirstChild();
8189
secondChild = node->getSecondChild();
8190
thirdChild = node->getChild(2);
8191
fourthChild = node->getChild(3);
8192
fifthChild = node->getChild(4);
8193
objReg = cg->evaluate(secondChild);
8194
8195
// VM helper chops off the value in 32bit, and we don't want the whole long value either
8196
if (thirdChild->getOpCode().isLoadConst() && thirdChild->getRegister() == NULL && comp->target().is32Bit())
8197
{
8198
offsetValue = thirdChild->getLongInt();
8199
offsetReg = cg->allocateRegister();
8200
loadConstant(cg, node, (int32_t) offsetValue, offsetReg);
8201
freeOffsetReg = true;
8202
}
8203
else
8204
{
8205
offsetReg = cg->evaluate(thirdChild);
8206
if (comp->target().is32Bit())
8207
offsetReg = offsetReg->getLowOrder();
8208
}
8209
8210
oldVReg = cg->evaluate(fourthChild);
8211
8212
TR::Node *translatedNode = fifthChild;
8213
bool bumpedRefCount = false;
8214
if (comp->useCompressedPointers() && (fifthChild->getDataType() != TR::Address))
8215
{
8216
bool useShiftedOffsets = (TR::Compiler->om.compressedReferenceShiftOffset() != 0);
8217
8218
translatedNode = fifthChild;
8219
if (translatedNode->getOpCode().isConversion())
8220
translatedNode = translatedNode->getFirstChild();
8221
if (translatedNode->getOpCode().isRightShift()) // optional
8222
translatedNode = translatedNode->getFirstChild();
8223
8224
translatedNode = fifthChild;
8225
if (useShiftedOffsets)
8226
{
8227
while ((translatedNode->getNumChildren() > 0) && (translatedNode->getOpCodeValue() != TR::a2l))
8228
translatedNode = translatedNode->getFirstChild();
8229
8230
if (translatedNode->getOpCodeValue() == TR::a2l)
8231
translatedNode = translatedNode->getFirstChild();
8232
8233
// this is required so that different registers are
8234
// allocated for the actual store and translated values
8235
translatedNode->incReferenceCount();
8236
bumpedRefCount = true;
8237
}
8238
}
8239
8240
newVReg = cg->evaluate(fifthChild);
8241
if (objReg == newVReg)
8242
{
8243
newVReg = cg->allocateCollectedReferenceRegister();
8244
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, newVReg, objReg);
8245
needDup = true;
8246
}
8247
cndReg = cg->allocateRegister(TR_CCR);
8248
doneLabel = generateLabelSymbol(cg);
8249
storeLabel = generateLabelSymbol(cg);
8250
8251
if (comp->getOptions()->realTimeGC())
8252
wrtBarEndLabel = storeLabel;
8253
else
8254
wrtBarEndLabel = doneLabel;
8255
8256
#ifdef OMR_GC_CONCURRENT_SCAVENGER
8257
if (TR::Compiler->om.readBarrierType() != gc_modron_readbar_none)
8258
{
8259
TR::Register *tmpReg = cg->allocateRegister();
8260
TR::Register *locationReg = cg->allocateRegister();
8261
TR::Register *evacuateReg = cg->allocateRegister();
8262
TR::Register *r3Reg = cg->allocateRegister();
8263
TR::Register *r11Reg = cg->allocateRegister();
8264
TR::Register *metaReg = cg->getMethodMetaDataRegister();
8265
8266
TR::LabelSymbol *startReadBarrierLabel = generateLabelSymbol(cg);
8267
TR::LabelSymbol *endReadBarrierLabel = generateLabelSymbol(cg);
8268
8269
TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 9, cg->trMemory());
8270
deps->addPostCondition(objReg, TR::RealRegister::NoReg);
8271
deps->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0();
8272
deps->addPostCondition(offsetReg, TR::RealRegister::NoReg);
8273
deps->addPostCondition(tmpReg, TR::RealRegister::NoReg);
8274
deps->addPostCondition(locationReg, TR::RealRegister::gr4); //TR_softwareReadBarrier helper needs this in gr4.
8275
deps->addPostCondition(evacuateReg, TR::RealRegister::NoReg);
8276
deps->addPostCondition(r3Reg, TR::RealRegister::gr3);
8277
deps->addPostCondition(r11Reg, TR::RealRegister::gr11);
8278
deps->addPostCondition(metaReg, TR::RealRegister::NoReg);
8279
deps->addPostCondition(cndReg, TR::RealRegister::NoReg);
8280
8281
startReadBarrierLabel->setStartInternalControlFlow();
8282
endReadBarrierLabel->setEndInternalControlFlow();
8283
8284
TR::InstOpCode::Mnemonic loadOpCode = TR::InstOpCode::lwz;
8285
TR::InstOpCode::Mnemonic cmpOpCode = TR::InstOpCode::cmpl4;
8286
int32_t loadWidth = 4;
8287
8288
if (comp->target().is64Bit() && !comp->useCompressedPointers())
8289
{
8290
loadOpCode = TR::InstOpCode::ld;
8291
cmpOpCode = TR::InstOpCode::cmpl8;
8292
loadWidth = 8;
8293
}
8294
8295
generateTrg1MemInstruction(cg, loadOpCode, node, tmpReg, TR::MemoryReference::createWithIndexReg(cg, objReg, offsetReg, loadWidth));
8296
8297
generateLabelInstruction(cg, TR::InstOpCode::label, node, startReadBarrierLabel);
8298
8299
generateTrg1MemInstruction(cg, loadOpCode, node, evacuateReg,
8300
TR::MemoryReference::createWithDisplacement(cg, metaReg, comp->fej9()->thisThreadGetEvacuateBaseAddressOffset(), loadWidth));
8301
generateTrg1Src2Instruction(cg, cmpOpCode, node, cndReg, tmpReg, evacuateReg);
8302
generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, endReadBarrierLabel, cndReg);
8303
8304
generateTrg1MemInstruction(cg, loadOpCode, node, evacuateReg,
8305
TR::MemoryReference::createWithDisplacement(cg, metaReg, comp->fej9()->thisThreadGetEvacuateTopAddressOffset(), loadWidth));
8306
generateTrg1Src2Instruction(cg, cmpOpCode, node, cndReg, tmpReg, evacuateReg);
8307
generateConditionalBranchInstruction(cg, TR::InstOpCode::bgt, node, endReadBarrierLabel, cndReg);
8308
8309
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, locationReg, objReg, offsetReg);
8310
8311
// TR_softwareReadBarrier helper expects the vmThread in r3.
8312
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, r3Reg, metaReg);
8313
8314
TR::SymbolReference *helperSym = comp->getSymRefTab()->findOrCreateRuntimeHelper(TR_softwareReadBarrier);
8315
generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)helperSym->getMethodAddress(), deps, helperSym);
8316
8317
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, endReadBarrierLabel, deps);
8318
8319
cg->stopUsingRegister(tmpReg);
8320
cg->stopUsingRegister(locationReg);
8321
cg->stopUsingRegister(evacuateReg);
8322
cg->stopUsingRegister(r11Reg);
8323
cg->stopUsingRegister(r3Reg);
8324
8325
cg->machine()->setLinkRegisterKilled(true);
8326
}
8327
#endif //OMR_GC_CONCURRENT_SCAVENGER
8328
8329
if (!comp->getOptions()->realTimeGC())
8330
resultReg = genCAS(node, cg, objReg, offsetReg, oldVReg, newVReg, cndReg, doneLabel, secondChild, 0, true, (comp->target().is64Bit() && !comp->useCompressedPointers()));
8331
8332
uint32_t numDeps = (doWrtBar || doCrdMrk) ? 13 : 11;
8333
8334
if (doWrtBar) //two extra deps for space boundaries
8335
numDeps += 2;
8336
8337
conditions = createConditionsAndPopulateVSXDeps(cg, numDeps);
8338
8339
if (doWrtBar && doCrdMrk)
8340
{
8341
TR::Register *temp1Reg = cg->allocateRegister(), *temp2Reg = cg->allocateRegister(), *temp3Reg, *temp4Reg = cg->allocateRegister();
8342
TR::addDependency(conditions, objReg, TR::RealRegister::gr3, TR_GPR, cg);
8343
TR::Register *wrtbarSrcReg;
8344
if (translatedNode != fifthChild)
8345
{
8346
TR::addDependency(conditions, newVReg, TR::RealRegister::NoReg, TR_GPR, cg);
8347
TR::addDependency(conditions, translatedNode->getRegister(), TR::RealRegister::gr4, TR_GPR, cg);
8348
wrtbarSrcReg = translatedNode->getRegister();
8349
}
8350
else
8351
{
8352
TR::addDependency(conditions, newVReg, TR::RealRegister::gr4, TR_GPR, cg);
8353
wrtbarSrcReg = newVReg;
8354
}
8355
8356
TR::addDependency(conditions, temp1Reg, TR::RealRegister::gr11, TR_GPR, cg);
8357
TR::addDependency(conditions, temp2Reg, TR::RealRegister::NoReg, TR_GPR, cg);
8358
TR::addDependency(conditions, offsetReg, TR::RealRegister::NoReg, TR_GPR, cg);
8359
TR::addDependency(conditions, temp4Reg, TR::RealRegister::NoReg, TR_GPR, cg);
8360
8361
if (freeOffsetReg)
8362
{
8363
temp3Reg = offsetReg;
8364
}
8365
else
8366
{
8367
temp3Reg = cg->allocateRegister();
8368
TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);
8369
}
8370
8371
if (!fifthChild->isNonNull())
8372
{
8373
generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpi, node, cndReg, newVReg, NULLVALUE);
8374
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, doneLabel, cndReg);
8375
}
8376
8377
VMnonNullSrcWrtBarCardCheckEvaluator(node, comp->useCompressedPointers() ? wrtbarSrcReg : newVReg, objReg, cndReg, temp1Reg, temp2Reg, temp3Reg, temp4Reg, doneLabel,
8378
conditions, comp->useCompressedPointers(), cg);
8379
8380
cg->stopUsingRegister(temp1Reg);
8381
cg->stopUsingRegister(temp2Reg);
8382
if (!freeOffsetReg)
8383
cg->stopUsingRegister(temp3Reg);
8384
cg->stopUsingRegister(temp4Reg);
8385
}
8386
else if (doWrtBar && !doCrdMrk)
8387
{
8388
TR::Register *temp1Reg = cg->allocateRegister(), *temp2Reg;
8389
TR::addDependency(conditions, objReg, TR::RealRegister::gr3, TR_GPR, cg);
8390
8391
if (newVReg != translatedNode->getRegister())
8392
{
8393
TR::addDependency(conditions, newVReg, TR::RealRegister::NoReg, TR_GPR, cg);
8394
if (comp->getOptions()->realTimeGC())
8395
TR::addDependency(conditions, translatedNode->getRegister(), TR::RealRegister::gr5, TR_GPR, cg);
8396
else
8397
TR::addDependency(conditions, translatedNode->getRegister(), TR::RealRegister::gr4, TR_GPR, cg);
8398
}
8399
else
8400
{
8401
if (comp->getOptions()->realTimeGC())
8402
TR::addDependency(conditions, newVReg, TR::RealRegister::gr5, TR_GPR, cg);
8403
else
8404
TR::addDependency(conditions, newVReg, TR::RealRegister::gr4, TR_GPR, cg);
8405
}
8406
8407
TR::addDependency(conditions, temp1Reg, TR::RealRegister::NoReg, TR_GPR, cg);
8408
8409
//Realtime needs the offsetReg to be preserved after the wrtbar to do the store in genCAS()
8410
if (freeOffsetReg && !comp->getOptions()->realTimeGC())
8411
{
8412
TR::addDependency(conditions, offsetReg, TR::RealRegister::gr11, TR_GPR, cg);
8413
temp2Reg = offsetReg;
8414
}
8415
else
8416
{
8417
temp2Reg = cg->allocateRegister();
8418
TR::addDependency(conditions, temp2Reg, TR::RealRegister::gr11, TR_GPR, cg);
8419
TR::addDependency(conditions, offsetReg, TR::RealRegister::NoReg, TR_GPR, cg);
8420
}
8421
8422
if (!fifthChild->isNonNull())
8423
{
8424
generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpi, node, cndReg, newVReg, NULLVALUE);
8425
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, wrtBarEndLabel, cndReg);
8426
}
8427
8428
TR::Register *dstAddrReg = NULL;
8429
8430
if (comp->getOptions()->realTimeGC())
8431
{
8432
dstAddrReg = cg->allocateRegister();
8433
TR::addDependency(conditions, dstAddrReg, TR::RealRegister::gr4, TR_GPR, cg);
8434
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, dstAddrReg, objReg, offsetReg);
8435
}
8436
8437
VMnonNullSrcWrtBarCardCheckEvaluator(node, comp->useCompressedPointers() ? translatedNode->getRegister() : newVReg, objReg, cndReg, temp1Reg, temp2Reg, dstAddrReg, NULL,
8438
wrtBarEndLabel, conditions, comp->useCompressedPointers(), cg);
8439
8440
if (comp->getOptions()->realTimeGC())
8441
cg->stopUsingRegister(dstAddrReg);
8442
8443
cg->stopUsingRegister(temp1Reg);
8444
if (!freeOffsetReg || comp->getOptions()->realTimeGC())
8445
cg->stopUsingRegister(temp2Reg);
8446
}
8447
else if (!doWrtBar && doCrdMrk)
8448
{
8449
TR::Register *temp1Reg = cg->allocateRegister(), *temp2Reg = cg->allocateRegister(), *temp3Reg;
8450
TR::addDependency(conditions, objReg, TR::RealRegister::NoReg, TR_GPR, cg);
8451
conditions->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0();
8452
TR::addDependency(conditions, temp1Reg, TR::RealRegister::NoReg, TR_GPR, cg);
8453
conditions->getPostConditions()->getRegisterDependency(1)->setExcludeGPR0();
8454
if (newVReg != translatedNode->getRegister())
8455
TR::addDependency(conditions, newVReg, TR::RealRegister::NoReg, TR_GPR, cg);
8456
TR::addDependency(conditions, translatedNode->getRegister(), TR::RealRegister::NoReg, TR_GPR, cg);
8457
8458
TR::addDependency(conditions, temp2Reg, TR::RealRegister::NoReg, TR_GPR, cg);
8459
TR::addDependency(conditions, offsetReg, TR::RealRegister::NoReg, TR_GPR, cg);
8460
if (freeOffsetReg)
8461
{
8462
temp3Reg = offsetReg;
8463
}
8464
else
8465
{
8466
temp3Reg = cg->allocateRegister();
8467
TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);
8468
}
8469
8470
VMCardCheckEvaluator(node, objReg, cndReg, temp1Reg, temp2Reg, temp3Reg, conditions, cg);
8471
8472
cg->stopUsingRegister(temp1Reg);
8473
cg->stopUsingRegister(temp2Reg);
8474
if (!freeOffsetReg)
8475
cg->stopUsingRegister(temp3Reg);
8476
}
8477
else
8478
{
8479
TR::addDependency(conditions, objReg, TR::RealRegister::NoReg, TR_GPR, cg);
8480
conditions->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0();
8481
TR::addDependency(conditions, offsetReg, TR::RealRegister::NoReg, TR_GPR, cg);
8482
if (newVReg != translatedNode->getRegister())
8483
TR::addDependency(conditions, newVReg, TR::RealRegister::NoReg, TR_GPR, cg);
8484
TR::addDependency(conditions, translatedNode->getRegister(), TR::RealRegister::NoReg, TR_GPR, cg);
8485
}
8486
8487
generateLabelInstruction(cg, TR::InstOpCode::label, node, storeLabel);
8488
8489
if (comp->getOptions()->realTimeGC())
8490
resultReg = genCAS(node, cg, objReg, offsetReg, oldVReg, newVReg, cndReg, doneLabel, secondChild, 0, true, (comp->target().is64Bit() && !comp->useCompressedPointers()));
8491
8492
TR::addDependency(conditions, resultReg, TR::RealRegister::NoReg, TR_GPR, cg);
8493
if (oldVReg != newVReg && oldVReg != objReg)
8494
TR::addDependency(conditions, oldVReg, TR::RealRegister::NoReg, TR_GPR, cg);
8495
TR::addDependency(conditions, cndReg, TR::RealRegister::cr0, TR_CCR, cg);
8496
8497
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);
8498
8499
if (needDup)
8500
cg->stopUsingRegister(newVReg);
8501
cg->stopUsingRegister(cndReg);
8502
cg->recursivelyDecReferenceCount(firstChild);
8503
cg->decReferenceCount(secondChild);
8504
if (freeOffsetReg)
8505
{
8506
cg->stopUsingRegister(offsetReg);
8507
cg->recursivelyDecReferenceCount(thirdChild);
8508
}
8509
else
8510
cg->decReferenceCount(thirdChild);
8511
cg->decReferenceCount(fourthChild);
8512
cg->decReferenceCount(fifthChild);
8513
if (bumpedRefCount)
8514
cg->decReferenceCount(translatedNode);
8515
8516
return resultReg;
8517
}
8518
8519
8520
void J9::Power::TreeEvaluator::restoreTOCRegister(TR::Node *node, TR::CodeGenerator *cg, TR::RegisterDependencyConditions *dependencies)
8521
{
8522
#if defined(TR_HOST_POWER)
8523
TR::Compilation *comp = cg->comp();
8524
TR::Register *tocReg = dependencies->searchPreConditionRegister(TR::RealRegister::gr2);
8525
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, tocReg,
8526
TR::MemoryReference::createWithDisplacement(cg, cg->getMethodMetaDataRegister(), offsetof(J9VMThread, jitTOC), TR::Compiler->om.sizeofReferenceAddress()));
8527
#else
8528
TR_ASSERT(0, "direct C calls directly are not supported on this platform.\n");
8529
#endif
8530
}
8531
8532
void J9::Power::TreeEvaluator::buildArgsProcessFEDependencies(TR::Node *node, TR::CodeGenerator *cg, TR::RegisterDependencyConditions *dependencies)
8533
{
8534
TR::Compilation *comp = cg->comp();
8535
//Java uses gr2 as a volatile for targets except for 32-bit Linux.
8536
bool aix_style_linkage = (comp->target().isAIX() || (comp->target().is64Bit() && comp->target().isLinux()));
8537
8538
if(aix_style_linkage)
8539
TR::addDependency(dependencies, NULL, TR::RealRegister::gr2, TR_GPR, cg);
8540
}
8541
8542
TR::Register *J9::Power::TreeEvaluator::retrieveTOCRegister(TR::Node *node, TR::CodeGenerator *cg, TR::RegisterDependencyConditions *dependencies)
8543
{
8544
#if defined(DEBUG)
8545
TR::Compilation *comp = cg->comp();
8546
//We should not land here if we're compiling for 32-bit Linux.
8547
bool aix_style_linkage = (comp->target().isAIX() || (comp->target().is64Bit() && comp->target().isLinux()));
8548
TR_ASSERT(aix_style_linkage, "Landed to restore gr2 for TOC with 32bit Linux as target\n");
8549
#endif
8550
8551
TR::Register *grTOCReg=dependencies->searchPreConditionRegister(TR::RealRegister::gr2);
8552
TR_ASSERT(grTOCReg != NULL, "Dependency not set in J9 Java on gr2 for TOC.\n");
8553
return grTOCReg;
8554
}
8555
8556
8557
static TR::Register *inlineAtomicOps(TR::Node *node, TR::CodeGenerator *cg, int8_t size, TR::MethodSymbol *method, bool isArray)
8558
{
8559
TR::Node *valueChild = node->getFirstChild();
8560
TR::Node *deltaChild = NULL;
8561
TR::Register *valueReg = cg->evaluate(valueChild);
8562
TR::Register *deltaReg = NULL;
8563
TR::Register *resultReg = cg->allocateRegister();
8564
TR::Register *cndReg = cg->allocateRegister(TR_CCR);
8565
TR::Register *fieldOffsetReg = cg->allocateRegister();
8566
TR::Register *tempReg = NULL;
8567
int32_t delta = 0;
8568
int32_t numDeps = 5;
8569
TR::Compilation *comp = cg->comp();
8570
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());
8571
8572
bool isAddOp = true;
8573
bool isGetAndOp = true;
8574
bool isLong = false;
8575
bool isArgConstant = false;
8576
bool isArgImmediate = false;
8577
bool isArgImmediateShifted = false;
8578
TR::RecognizedMethod currentMethod = method->getRecognizedMethod();
8579
8580
switch (currentMethod)
8581
{
8582
case TR::java_util_concurrent_atomic_AtomicBoolean_getAndSet:
8583
case TR::java_util_concurrent_atomic_AtomicInteger_getAndSet:
8584
case TR::java_util_concurrent_atomic_AtomicLong_getAndSet:
8585
case TR::java_util_concurrent_atomic_AtomicReference_getAndSet:
8586
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndSet:
8587
case TR::java_util_concurrent_atomic_AtomicLongArray_getAndSet:
8588
case TR::java_util_concurrent_atomic_AtomicReferenceArray_getAndSet:
8589
{
8590
isAddOp = false;
8591
break;
8592
}
8593
case TR::java_util_concurrent_atomic_AtomicInteger_addAndGet:
8594
case TR::java_util_concurrent_atomic_AtomicIntegerArray_addAndGet:
8595
{
8596
isGetAndOp = false;
8597
}
8598
case TR::java_util_concurrent_atomic_AtomicInteger_getAndAdd:
8599
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndAdd:
8600
{
8601
break;
8602
}
8603
8604
case TR::java_util_concurrent_atomic_AtomicInteger_incrementAndGet:
8605
case TR::java_util_concurrent_atomic_AtomicIntegerArray_incrementAndGet:
8606
{
8607
isGetAndOp = false;
8608
}
8609
case TR::java_util_concurrent_atomic_AtomicInteger_getAndIncrement:
8610
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndIncrement:
8611
{
8612
delta = (int32_t) 1;
8613
isArgConstant = true;
8614
isArgImmediate = true;
8615
break;
8616
}
8617
case TR::java_util_concurrent_atomic_AtomicInteger_decrementAndGet:
8618
case TR::java_util_concurrent_atomic_AtomicIntegerArray_decrementAndGet:
8619
{
8620
isGetAndOp = false;
8621
}
8622
case TR::java_util_concurrent_atomic_AtomicInteger_getAndDecrement:
8623
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndDecrement:
8624
{
8625
delta = (int32_t) - 1;
8626
isArgConstant = true;
8627
isArgImmediate = true;
8628
break;
8629
}
8630
}
8631
8632
if (node->getNumChildren() > 1)
8633
deltaChild = node->getSecondChild();
8634
8635
//determine if the delta is a constant.
8636
if (deltaChild && deltaChild->getOpCode().isLoadConst() && !deltaChild->getRegister() && deltaChild->getDataType() == TR::Int32)
8637
{
8638
delta = (int32_t)(deltaChild->getInt());
8639
isArgConstant = true;
8640
8641
//determine if the constant can be represented as an immediate
8642
if (delta <= UPPER_IMMED && delta >= LOWER_IMMED)
8643
{
8644
// avoid evaluating immediates for add operations
8645
isArgImmediate = true;
8646
}
8647
else if (delta & 0xFFFF == 0 && (delta & 0xFFFF0000) >> 16 <= UPPER_IMMED && (delta & 0xFFFF0000) >> 16 >= LOWER_IMMED)
8648
{
8649
// avoid evaluating shifted immediates for add operations
8650
isArgImmediate = true;
8651
isArgImmediateShifted = true;
8652
}
8653
else
8654
{
8655
// evaluate non-immediate constants since there may be reuse
8656
// and they have to go into a reg anyway
8657
tempReg = cg->evaluate(deltaChild);
8658
}
8659
}
8660
else if (deltaChild)
8661
tempReg = cg->evaluate(deltaChild);
8662
8663
//determine the offset of the value field
8664
int32_t fieldOffset = 0;
8665
int32_t shiftAmount = 0;
8666
TR::Node *indexChild = NULL;
8667
TR::Register *indexRegister = NULL;
8668
8669
TR::Register *scratchRegister = NULL;
8670
8671
if (!isArray)
8672
{
8673
TR_OpaqueClassBlock * bdClass;
8674
char *className, *fieldSig;
8675
int32_t classNameLen, fieldSigLen;
8676
8677
fieldSigLen = 1;
8678
8679
switch (currentMethod)
8680
{
8681
case TR::java_util_concurrent_atomic_AtomicBoolean_getAndSet:
8682
className = "Ljava/util/concurrent/atomic/AtomicBoolean;";
8683
classNameLen = 43;
8684
fieldSig = "I"; // not a typo, the field is int
8685
break;
8686
case TR::java_util_concurrent_atomic_AtomicInteger_getAndSet:
8687
case TR::java_util_concurrent_atomic_AtomicInteger_addAndGet:
8688
case TR::java_util_concurrent_atomic_AtomicInteger_getAndAdd:
8689
case TR::java_util_concurrent_atomic_AtomicInteger_incrementAndGet:
8690
case TR::java_util_concurrent_atomic_AtomicInteger_getAndIncrement:
8691
case TR::java_util_concurrent_atomic_AtomicInteger_decrementAndGet:
8692
case TR::java_util_concurrent_atomic_AtomicInteger_getAndDecrement:
8693
className = "Ljava/util/concurrent/atomic/AtomicInteger;";
8694
classNameLen = 43;
8695
fieldSig = "I";
8696
break;
8697
case TR::java_util_concurrent_atomic_AtomicLong_getAndSet:
8698
case TR::java_util_concurrent_atomic_AtomicLong_addAndGet:
8699
case TR::java_util_concurrent_atomic_AtomicLong_getAndAdd:
8700
case TR::java_util_concurrent_atomic_AtomicLong_incrementAndGet:
8701
case TR::java_util_concurrent_atomic_AtomicLong_getAndIncrement:
8702
case TR::java_util_concurrent_atomic_AtomicLong_decrementAndGet:
8703
case TR::java_util_concurrent_atomic_AtomicLong_getAndDecrement:
8704
className = "Ljava/util/concurrent/atomic/AtomicLong;";
8705
classNameLen = 40;
8706
fieldSig = "J";
8707
break;
8708
case TR::java_util_concurrent_atomic_AtomicReference_getAndSet:
8709
className = "Ljava/util/concurrent/atomic/AtomicReference;";
8710
classNameLen = 45;
8711
fieldSig = "Ljava/lang/Object;";
8712
fieldSigLen = 18;
8713
break;
8714
default:
8715
TR_ASSERT(0, "Unknown atomic operation method\n");
8716
return NULL;
8717
}
8718
8719
TR_ResolvedMethod *owningMethod = node->getSymbolReference()->getOwningMethod(comp);
8720
TR_OpaqueClassBlock *containingClass = fej9->getClassFromSignature(className, classNameLen, owningMethod, true);
8721
fieldOffset = fej9->getInstanceFieldOffset(containingClass, "value", 5, fieldSig, fieldSigLen, true) + fej9->getObjectHeaderSizeInBytes(); // size of a J9 object header
8722
}
8723
else
8724
{
8725
if (isArray)
8726
{
8727
indexChild = node->getChild(1);
8728
indexRegister = cg->evaluate(indexChild);
8729
fieldOffset = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();
8730
if (size == 4)
8731
shiftAmount = 2;
8732
else if (size == 8)
8733
shiftAmount = 3;
8734
8735
TR_OpaqueClassBlock * bdClass;
8736
char *className, *fieldSig;
8737
int32_t classNameLen, fieldSigLen;
8738
8739
fieldSigLen = 1;
8740
8741
switch (currentMethod)
8742
{
8743
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndSet:
8744
case TR::java_util_concurrent_atomic_AtomicIntegerArray_incrementAndGet:
8745
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndIncrement:
8746
case TR::java_util_concurrent_atomic_AtomicIntegerArray_decrementAndGet:
8747
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndDecrement:
8748
case TR::java_util_concurrent_atomic_AtomicIntegerArray_addAndGet:
8749
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndAdd:
8750
className = "Ljava/util/concurrent/atomic/AtomicIntegerArray;";
8751
classNameLen = 48;
8752
fieldSig = "[I";
8753
fieldSigLen = 2;
8754
break;
8755
8756
case TR::java_util_concurrent_atomic_AtomicLongArray_getAndSet:
8757
case TR::java_util_concurrent_atomic_AtomicLongArray_incrementAndGet:
8758
case TR::java_util_concurrent_atomic_AtomicLongArray_getAndIncrement:
8759
case TR::java_util_concurrent_atomic_AtomicLongArray_decrementAndGet:
8760
case TR::java_util_concurrent_atomic_AtomicLongArray_getAndDecrement:
8761
case TR::java_util_concurrent_atomic_AtomicLongArray_addAndGet:
8762
case TR::java_util_concurrent_atomic_AtomicLongArray_getAndAdd:
8763
className = "Ljava/util/concurrent/atomic/AtomicLongArray;";
8764
classNameLen = 45;
8765
fieldSig = "[J";
8766
fieldSigLen = 2;
8767
break;
8768
8769
case TR::java_util_concurrent_atomic_AtomicReferenceArray_getAndSet:
8770
className = "Ljava/util/concurrent/atomic/AtomicReferenceArray;";
8771
classNameLen = 50;
8772
fieldSig = "Ljava/lang/Object;";
8773
fieldSigLen = 18;
8774
break;
8775
}
8776
8777
TR_ResolvedMethod *owningMethod = node->getSymbolReference()->getOwningMethod(comp);
8778
TR_OpaqueClassBlock *containingClass = fej9->getClassFromSignature(className, classNameLen, owningMethod, true);
8779
int32_t arrayFieldOffset = fej9->getInstanceFieldOffset(containingClass, "array", 5, fieldSig, fieldSigLen) + fej9->getObjectHeaderSizeInBytes(); // size of a J9 object header
8780
8781
TR::MemoryReference *tempMR = TR::MemoryReference::createWithDisplacement(cg, valueReg, arrayFieldOffset, isLong ? 8 : 4);
8782
8783
numDeps++;
8784
scratchRegister = cg->allocateCollectedReferenceRegister();
8785
TR::Register *memRefRegister = scratchRegister;
8786
8787
if (TR::Compiler->om.compressObjectReferences())
8788
// read only 32 bits
8789
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, memRefRegister,
8790
TR::MemoryReference::createWithDisplacement(cg, valueReg, arrayFieldOffset, 4));
8791
else
8792
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, memRefRegister, TR::MemoryReference::createWithDisplacement(cg, valueReg, arrayFieldOffset, TR::Compiler->om.sizeofReferenceAddress()));
8793
8794
valueReg = memRefRegister;
8795
8796
generateShiftLeftImmediate(cg, node, fieldOffsetReg, indexRegister, shiftAmount);
8797
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, fieldOffsetReg, fieldOffsetReg, fieldOffset);
8798
}
8799
}
8800
8801
// Memory barrier --- NOTE: we should be able to do a test upfront to save this barrier,
8802
// but Hursley advised to be conservative due to lack of specification.
8803
generateInstruction(cg, TR::InstOpCode::lwsync, node);
8804
8805
TR::LabelSymbol *doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
8806
TR::LabelSymbol *loopLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
8807
8808
loopLabel->setStartInternalControlFlow();
8809
if (!isArray)
8810
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, fieldOffsetReg, fieldOffset);
8811
8812
deltaReg = cg->allocateRegister();
8813
if (isArgImmediate && isAddOp)
8814
{
8815
// If argument is an immediate value and operation is an add,
8816
// it will be used as an immediate operand in an add immediate instruction
8817
generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);
8818
}
8819
else if (isArgImmediate)
8820
{
8821
// If argument is immediate, but the operation is not an add,
8822
// the value must still be loaded into a register
8823
generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);
8824
loadConstant(cg, node, delta, deltaReg);
8825
}
8826
else
8827
{
8828
// For non-constant arguments, use evaluated register
8829
// For non-immediate constants, evaluate since they may be re-used
8830
numDeps++;
8831
generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);
8832
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, deltaReg, tempReg);
8833
}
8834
8835
generateTrg1MemInstruction(cg, isLong ? TR::InstOpCode::ldarx : TR::InstOpCode::lwarx, node, resultReg,
8836
TR::MemoryReference::createWithIndexReg(cg, valueReg, fieldOffsetReg, isLong ? 8 : 4));
8837
8838
if (isAddOp)
8839
{
8840
if (isArgImmediateShifted)
8841
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addis, node, deltaReg, resultReg, ((delta & 0xFFFF0000) >> 16));
8842
else if (isArgImmediate)
8843
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, deltaReg, resultReg, delta);
8844
else
8845
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, deltaReg, resultReg, deltaReg);
8846
}
8847
8848
generateMemSrc1Instruction(cg, isLong ? TR::InstOpCode::stdcx_r : TR::InstOpCode::stwcx_r, node, TR::MemoryReference::createWithIndexReg(cg, valueReg, fieldOffsetReg, isLong ? 8 : 4),
8849
deltaReg);
8850
8851
// We expect this store is usually successful, i.e., the following branch will not be taken
8852
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, loopLabel, cndReg);
8853
8854
// We deviate from the VM helper here: no-store-no-barrier instead of always-barrier
8855
generateInstruction(cg, TR::InstOpCode::sync, node);
8856
8857
TR::RegisterDependencyConditions *conditions;
8858
8859
//Set the conditions and dependencies
8860
conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, (uint16_t) numDeps, cg->trMemory());
8861
conditions->addPostCondition(valueReg, TR::RealRegister::NoReg);
8862
conditions->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0();
8863
conditions->addPostCondition(resultReg, TR::RealRegister::NoReg);
8864
conditions->getPostConditions()->getRegisterDependency(1)->setExcludeGPR0();
8865
conditions->addPostCondition(deltaReg, TR::RealRegister::NoReg);
8866
conditions->addPostCondition(cndReg, TR::RealRegister::cr0);
8867
conditions->addPostCondition(fieldOffsetReg, TR::RealRegister::NoReg);
8868
if (tempReg)
8869
conditions->addPostCondition(tempReg, TR::RealRegister::NoReg);
8870
if (scratchRegister)
8871
conditions->addPostCondition(scratchRegister, TR::RealRegister::NoReg);
8872
8873
doneLabel->setEndInternalControlFlow();
8874
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);
8875
8876
cg->decReferenceCount(valueChild);
8877
cg->stopUsingRegister(cndReg);
8878
cg->stopUsingRegister(fieldOffsetReg);
8879
8880
if (tempReg)
8881
cg->stopUsingRegister(tempReg);
8882
8883
if (scratchRegister)
8884
cg->stopUsingRegister(scratchRegister);
8885
8886
if (deltaChild)
8887
cg->decReferenceCount(deltaChild);
8888
8889
if (isGetAndOp)
8890
{
8891
//for Get And Op, we will store the result in the result register
8892
cg->stopUsingRegister(deltaReg);
8893
node->setRegister(resultReg);
8894
return resultReg;
8895
}
8896
else
8897
{
8898
//for Op And Get, we will store the return value in the delta register
8899
//we no longer need the result register
8900
cg->stopUsingRegister(resultReg);
8901
node->setRegister(deltaReg);
8902
return deltaReg;
8903
}
8904
}
8905
8906
static TR::Register *inlineSinglePrecisionFP(TR::Node *node, TR::InstOpCode::Mnemonic op, TR::CodeGenerator *cg)
8907
{
8908
TR_ASSERT(node->getNumChildren() == 1, "Wrong number of children in inlineSinglePrecisionFP");
8909
8910
TR::Node *firstChild = node->getFirstChild();
8911
TR::Register *srcRegister = cg->evaluate(firstChild);
8912
TR::Register *targetRegister = cg->allocateSinglePrecisionRegister();
8913
8914
generateTrg1Src1Instruction(cg, op, node, targetRegister, srcRegister);
8915
8916
node->setRegister(targetRegister);
8917
cg->decReferenceCount(firstChild);
8918
8919
return targetRegister;
8920
}
8921
8922
static TR::Register *inlineSinglePrecisionFPTrg1Src2(TR::Node *node, TR::InstOpCode::Mnemonic op, TR::CodeGenerator *cg)
8923
{
8924
TR_ASSERT(node->getNumChildren() == 2, "Wrong number of children in inlineSinglePrecisionFPTrg1Src2");
8925
8926
TR::Node *firstChild = node->getFirstChild();
8927
TR::Node *secondChild = node->getSecondChild();
8928
TR::Register *src1Register = cg->evaluate(firstChild);
8929
TR::Register *src2Register = cg->evaluate(secondChild);
8930
TR::Register *targetRegister = cg->allocateSinglePrecisionRegister();
8931
8932
if (op == TR::InstOpCode::fcpsgn) // fcpsgn orders operands opposite of Math.copySign
8933
generateTrg1Src2Instruction(cg, op, node, targetRegister, src2Register, src1Register);
8934
else
8935
generateTrg1Src2Instruction(cg, op, node, targetRegister, src1Register, src2Register);
8936
8937
node->setRegister(targetRegister);
8938
cg->decReferenceCount(firstChild);
8939
cg->decReferenceCount(secondChild);
8940
return targetRegister;
8941
}
8942
8943
static TR::Register *inlineFPTrg1Src3(TR::Node *node, TR::InstOpCode::Mnemonic op, TR::CodeGenerator *cg)
8944
{
8945
TR_ASSERT_FATAL(node->getNumChildren() == 3, "In function inlineFPTrg1Src3, the node at address %p should have exactly 3 children, but got %u instead", node, node->getNumChildren());
8946
8947
TR::DataType type = node->getDataType();
8948
TR_ASSERT_FATAL(type == TR::Float || type == TR::Double, "In function inlineFPTrg1Src3, the node at address %p should be either TR::Float or TR::Double", node);
8949
8950
TR::Node *firstChild = node->getFirstChild();
8951
TR::Node *secondChild = node->getSecondChild();
8952
TR::Node *thirdChild = node->getThirdChild();
8953
TR::Register *src1Register = cg->evaluate(firstChild);
8954
TR::Register *src2Register = cg->evaluate(secondChild);
8955
TR::Register *src3Register = cg->evaluate(thirdChild);
8956
TR::Register *targetRegister;
8957
8958
if(type == TR::Float)
8959
targetRegister = cg->allocateSinglePrecisionRegister();
8960
else
8961
targetRegister = cg->allocateRegister(TR_FPR);
8962
8963
generateTrg1Src3Instruction(cg, op, node, targetRegister, src1Register, src2Register, src3Register);
8964
8965
node->setRegister(targetRegister);
8966
cg->decReferenceCount(firstChild);
8967
cg->decReferenceCount(secondChild);
8968
cg->decReferenceCount(thirdChild);
8969
return targetRegister;
8970
}
8971
8972
static TR::Register *inlineDoublePrecisionFP(TR::Node *node, TR::InstOpCode::Mnemonic op, TR::CodeGenerator *cg)
8973
{
8974
TR_ASSERT(node->getNumChildren() == 1, "Wrong number of children in inlineDoublePrecisionFP");
8975
8976
TR::Node *firstChild = node->getFirstChild();
8977
TR::Register *srcRegister = cg->evaluate(firstChild);
8978
TR::Register *targetRegister = cg->allocateRegister(TR_FPR);
8979
8980
generateTrg1Src1Instruction(cg, op, node, targetRegister, srcRegister);
8981
8982
node->setRegister(targetRegister);
8983
cg->decReferenceCount(firstChild);
8984
8985
return targetRegister;
8986
}
8987
8988
static TR::Register *inlineDoublePrecisionFPTrg1Src2(TR::Node *node, TR::InstOpCode::Mnemonic op, TR::CodeGenerator *cg)
8989
{
8990
TR_ASSERT(node->getNumChildren() == 2, "Wrong number of children in inlineDoublePrecisionFPTrg1Src2");
8991
8992
TR::Node *firstChild = node->getFirstChild();
8993
TR::Node *secondChild = node->getSecondChild();
8994
TR::Register *src1Register = cg->evaluate(firstChild);
8995
TR::Register *src2Register = cg->evaluate(secondChild);
8996
TR::Register *targetRegister = cg->allocateRegister(TR_FPR);
8997
8998
if (op == TR::InstOpCode::fcpsgn) // fcpsgn orders operands opposite of Math.copySign
8999
generateTrg1Src2Instruction(cg, op, node, targetRegister, src2Register, src1Register);
9000
else
9001
generateTrg1Src2Instruction(cg, op, node, targetRegister, src1Register, src2Register);
9002
9003
node->setRegister(targetRegister);
9004
cg->decReferenceCount(firstChild);
9005
cg->decReferenceCount(secondChild);
9006
return targetRegister;
9007
}
9008
9009
static TR::Register *inlineAtomicOperation(TR::Node *node, TR::CodeGenerator *cg, TR::MethodSymbol *method)
9010
{
9011
TR::Node *firstChild = NULL;
9012
TR::Node *valueChild = NULL;
9013
TR::Node *indexChild = NULL;
9014
TR::Node *deltaChild = NULL;
9015
TR::Node *newValChild = NULL;
9016
TR::Node *expValChild = NULL;
9017
TR::Node *newRefChild = NULL;
9018
TR::Node *expRefChild = NULL;
9019
TR::Node *overNewNode = NULL;
9020
TR::Node *overExpNode = NULL;
9021
9022
TR::LabelSymbol *startLabel = NULL;
9023
TR::LabelSymbol *failLabel = NULL;
9024
TR::LabelSymbol *doneLabel = NULL;
9025
9026
TR::Register *valueReg = NULL;
9027
TR::Register *scratchReg = NULL;
9028
TR::Register *fieldOffsetReg = NULL;
9029
TR::Register *cndReg = NULL;
9030
TR::Register *currentReg = NULL;
9031
TR::Register *newComposedReg = NULL;
9032
TR::Register *expComposedReg = NULL;
9033
TR::Register *expRefReg = NULL;
9034
TR::Register *newRefReg = NULL;
9035
TR::Register *expValReg = NULL;
9036
TR::Register *newValReg = NULL;
9037
TR::Register *resultReg = NULL;
9038
TR::Register *objReg = NULL;
9039
TR::Compilation *comp = cg->comp();
9040
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());
9041
9042
bool isArray = false;
9043
bool isAddOp = true;
9044
bool isDeltaImplied = false;
9045
bool isDelta = false;
9046
bool isGetAndOp = false;
9047
bool isCAS = false;
9048
bool isSetOnly = false;
9049
bool isWeak = false;
9050
bool isRefFirst = false;
9051
bool isUnsafe = false;
9052
9053
bool isArgImm = false;
9054
bool isArgImmShifted = false;
9055
9056
bool fieldOffsetRegIsEval = false;
9057
bool isRefWrite = false;
9058
9059
bool newPair = false;
9060
bool expPair = false;
9061
9062
bool stopNewComposedCopy = false;
9063
9064
int64_t expValImm;
9065
int32_t delta;
9066
uint8_t size = 4;
9067
int32_t fieldOffset = 0;
9068
int32_t idx;
9069
uint8_t numDeps = 1;
9070
9071
TR::RecognizedMethod currentMethod = method->getRecognizedMethod();
9072
9073
switch (currentMethod)
9074
{
9075
case TR::sun_misc_Unsafe_compareAndSwapLong_jlObjectJJJ_Z:
9076
size = 8;
9077
isUnsafe = true;
9078
isCAS = true;
9079
isAddOp = false;
9080
break;
9081
case TR::sun_misc_Unsafe_compareAndSwapObject_jlObjectJjlObjectjlObject_Z:
9082
size = TR::Compiler->om.sizeofReferenceAddress();
9083
isRefWrite = true;
9084
case TR::sun_misc_Unsafe_compareAndSwapInt_jlObjectJII_Z:
9085
isUnsafe = true;
9086
isCAS = true;
9087
isAddOp = false;
9088
break;
9089
case TR::java_util_concurrent_atomic_AtomicBoolean_getAndSet:
9090
case TR::java_util_concurrent_atomic_AtomicInteger_addAndGet:
9091
case TR::java_util_concurrent_atomic_AtomicInteger_decrementAndGet:
9092
case TR::java_util_concurrent_atomic_AtomicInteger_getAndAdd:
9093
case TR::java_util_concurrent_atomic_AtomicInteger_getAndDecrement:
9094
case TR::java_util_concurrent_atomic_AtomicInteger_getAndIncrement:
9095
case TR::java_util_concurrent_atomic_AtomicInteger_getAndSet:
9096
case TR::java_util_concurrent_atomic_AtomicInteger_incrementAndGet:
9097
case TR::java_util_concurrent_atomic_AtomicIntegerArray_addAndGet:
9098
case TR::java_util_concurrent_atomic_AtomicIntegerArray_decrementAndGet:
9099
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndAdd:
9100
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndDecrement:
9101
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndIncrement:
9102
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndSet:
9103
case TR::java_util_concurrent_atomic_AtomicIntegerArray_incrementAndGet:
9104
size = 4;
9105
break;
9106
case TR::java_util_concurrent_atomic_AtomicReference_getAndSet:
9107
case TR::java_util_concurrent_atomic_AtomicReferenceArray_getAndSet:
9108
size = TR::Compiler->om.sizeofReferenceAddress();
9109
break;
9110
default:
9111
size = 8;
9112
}
9113
9114
switch (currentMethod)
9115
{
9116
case TR::java_util_concurrent_atomic_AtomicBoolean_getAndSet:
9117
case TR::java_util_concurrent_atomic_AtomicInteger_getAndSet:
9118
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndSet:
9119
case TR::java_util_concurrent_atomic_AtomicLong_getAndSet:
9120
case TR::java_util_concurrent_atomic_AtomicLongArray_getAndSet:
9121
case TR::java_util_concurrent_atomic_AtomicReference_getAndSet:
9122
case TR::java_util_concurrent_atomic_AtomicReferenceArray_getAndSet:
9123
isAddOp = false;
9124
case TR::java_util_concurrent_atomic_AtomicInteger_getAndAdd:
9125
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndAdd:
9126
case TR::java_util_concurrent_atomic_AtomicLong_getAndAdd:
9127
case TR::java_util_concurrent_atomic_AtomicLongArray_getAndAdd:
9128
isDelta = true;
9129
case TR::java_util_concurrent_atomic_AtomicInteger_getAndDecrement:
9130
case TR::java_util_concurrent_atomic_AtomicInteger_getAndIncrement:
9131
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndDecrement:
9132
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndIncrement:
9133
case TR::java_util_concurrent_atomic_AtomicLong_getAndDecrement:
9134
case TR::java_util_concurrent_atomic_AtomicLong_getAndIncrement:
9135
case TR::java_util_concurrent_atomic_AtomicLongArray_getAndDecrement:
9136
case TR::java_util_concurrent_atomic_AtomicLongArray_getAndIncrement:
9137
isGetAndOp = true;
9138
break;
9139
case TR::java_util_concurrent_atomic_AtomicInteger_addAndGet:
9140
case TR::java_util_concurrent_atomic_AtomicIntegerArray_addAndGet:
9141
case TR::java_util_concurrent_atomic_AtomicLong_addAndGet:
9142
case TR::java_util_concurrent_atomic_AtomicLongArray_addAndGet:
9143
isDelta = true;
9144
break;
9145
}
9146
9147
isDeltaImplied = isAddOp && !isDelta;
9148
9149
if (isDeltaImplied)
9150
{
9151
switch (currentMethod)
9152
{
9153
case TR::java_util_concurrent_atomic_AtomicInteger_decrementAndGet:
9154
case TR::java_util_concurrent_atomic_AtomicInteger_getAndDecrement:
9155
case TR::java_util_concurrent_atomic_AtomicIntegerArray_decrementAndGet:
9156
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndDecrement:
9157
case TR::java_util_concurrent_atomic_AtomicLong_decrementAndGet:
9158
case TR::java_util_concurrent_atomic_AtomicLong_getAndDecrement:
9159
case TR::java_util_concurrent_atomic_AtomicLongArray_decrementAndGet:
9160
case TR::java_util_concurrent_atomic_AtomicLongArray_getAndDecrement:
9161
delta = (int32_t) - 1;
9162
default:
9163
delta = (int32_t) 1;
9164
}
9165
}
9166
9167
if (isUnsafe && isCAS)
9168
{
9169
firstChild = node->getChild(0);
9170
valueChild = node->getChild(1);
9171
indexChild = node->getChild(2);
9172
if (isRefWrite)
9173
{
9174
expRefChild = node->getChild(3);
9175
newRefChild = node->getChild(4);
9176
}
9177
else
9178
{
9179
expValChild = node->getChild(3);
9180
newValChild = node->getChild(4);
9181
}
9182
}
9183
else
9184
{
9185
valueChild = node->getChild(0);
9186
idx = 1;
9187
if (isArray)
9188
{
9189
indexChild = node->getChild(idx++);
9190
}
9191
if (isDelta)
9192
{
9193
deltaChild = node->getChild(idx++);
9194
}
9195
else if (isCAS)
9196
{
9197
expValChild = node->getChild(idx);
9198
newValChild = node->getChild(idx + 1);
9199
idx += 2;
9200
}
9201
if (idx != node->getNumChildren())
9202
{
9203
TR_ASSERT(0, "Wrong number of children for JUC Atomic node\n");
9204
return NULL;
9205
}
9206
}
9207
9208
valueReg = cg->evaluate(valueChild);
9209
objReg = valueReg;
9210
9211
if (isUnsafe)
9212
{
9213
if (indexChild->getOpCode().isLoadConst() && indexChild->getRegister() == NULL && comp->target().is32Bit())
9214
{
9215
fieldOffset = (int32_t) indexChild->getLongInt();
9216
//traceMsg(comp,"Allocate fieldOffsetReg\n");
9217
fieldOffsetReg = cg->allocateRegister();
9218
numDeps++;
9219
loadConstant(cg, node, fieldOffset, fieldOffsetReg);
9220
}
9221
else
9222
{
9223
fieldOffsetReg = cg->evaluate(indexChild);
9224
resultReg = cg->allocateRegister();
9225
numDeps += 2;
9226
if (comp->target().is32Bit())
9227
fieldOffsetReg = fieldOffsetReg->getLowOrder();
9228
}
9229
}
9230
else if (!isArray)
9231
{
9232
TR_OpaqueClassBlock *classBlock;
9233
char *className, *fieldSig;
9234
int32_t classNameLen, fieldSigLen;
9235
fieldSigLen = 1;
9236
9237
switch (currentMethod)
9238
{
9239
case TR::java_util_concurrent_atomic_AtomicBoolean_getAndSet:
9240
className = "Ljava/util/concurrent/atomic/AtomicBoolean;";
9241
classNameLen = 43;
9242
fieldSig = "I"; // not a type, the field is int
9243
case TR::java_util_concurrent_atomic_AtomicInteger_addAndGet:
9244
case TR::java_util_concurrent_atomic_AtomicInteger_decrementAndGet:
9245
case TR::java_util_concurrent_atomic_AtomicInteger_getAndAdd:
9246
case TR::java_util_concurrent_atomic_AtomicInteger_getAndDecrement:
9247
case TR::java_util_concurrent_atomic_AtomicInteger_getAndIncrement:
9248
case TR::java_util_concurrent_atomic_AtomicInteger_getAndSet:
9249
case TR::java_util_concurrent_atomic_AtomicInteger_incrementAndGet:
9250
className = "Ljava/util/concurrent/atomic/AtomicInteger;";
9251
classNameLen = 43;
9252
fieldSig = "I";
9253
break;
9254
case TR::java_util_concurrent_atomic_AtomicLong_addAndGet:
9255
case TR::java_util_concurrent_atomic_AtomicLong_decrementAndGet:
9256
case TR::java_util_concurrent_atomic_AtomicLong_getAndAdd:
9257
case TR::java_util_concurrent_atomic_AtomicLong_getAndDecrement:
9258
case TR::java_util_concurrent_atomic_AtomicLong_getAndIncrement:
9259
case TR::java_util_concurrent_atomic_AtomicLong_getAndSet:
9260
case TR::java_util_concurrent_atomic_AtomicLong_incrementAndGet:
9261
className = "Ljava/util/concurrent/atomic/AtomicLong;";
9262
classNameLen = 40;
9263
fieldSig = "J";
9264
break;
9265
case TR::java_util_concurrent_atomic_AtomicReference_getAndSet:
9266
className = "Ljava/util/concurrent/atomic/AtomicReference;";
9267
classNameLen = 45;
9268
fieldSig = "Ljava/lang/Object;";
9269
fieldSigLen = 18;
9270
break;
9271
default:
9272
TR_ASSERT(0, "Unknown atomic operation method\n");
9273
return NULL;
9274
}
9275
classBlock = fej9->getClassFromSignature(className, classNameLen, comp->getCurrentMethod(), true);
9276
fieldOffset = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock, "value", 5, fieldSig, fieldSigLen);
9277
}
9278
else // isArray
9279
{
9280
TR::Register *indexReg = cg->evaluate(indexChild);
9281
int32_t shiftAmount = size == 8 ? 3 : 2;
9282
fieldOffset = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();
9283
9284
TR_OpaqueClassBlock *classBlock;
9285
char *className, *fieldSig;
9286
int32_t classNameLen, fieldSigLen;
9287
fieldSigLen = 1;
9288
9289
switch (currentMethod)
9290
{
9291
case TR::java_util_concurrent_atomic_AtomicIntegerArray_addAndGet:
9292
case TR::java_util_concurrent_atomic_AtomicIntegerArray_decrementAndGet:
9293
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndAdd:
9294
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndDecrement:
9295
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndIncrement:
9296
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndSet:
9297
case TR::java_util_concurrent_atomic_AtomicIntegerArray_incrementAndGet:
9298
className = "Ljava/util/concurrent/atomic/AtomicIntegerArray;";
9299
classNameLen = 48;
9300
fieldSig = "[I";
9301
fieldSigLen = 2;
9302
break;
9303
case TR::java_util_concurrent_atomic_AtomicLongArray_addAndGet:
9304
case TR::java_util_concurrent_atomic_AtomicLongArray_decrementAndGet:
9305
case TR::java_util_concurrent_atomic_AtomicLongArray_getAndAdd:
9306
case TR::java_util_concurrent_atomic_AtomicLongArray_getAndDecrement:
9307
case TR::java_util_concurrent_atomic_AtomicLongArray_getAndIncrement:
9308
case TR::java_util_concurrent_atomic_AtomicLongArray_getAndSet:
9309
case TR::java_util_concurrent_atomic_AtomicLongArray_incrementAndGet:
9310
className = "Ljava/util/concurrent/atomic/AtomicLongArray;";
9311
classNameLen = 45;
9312
fieldSig = "[J";
9313
fieldSigLen = 2;
9314
break;
9315
case TR::java_util_concurrent_atomic_AtomicReferenceArray_getAndSet:
9316
className = "Ljava/util/concurrent/atomic/AtomicReferenceArray;";
9317
classNameLen = 50;
9318
fieldSig = "[Ljava/lang/Object;";
9319
fieldSigLen = 19;
9320
break;
9321
default:
9322
TR_ASSERT(0, "Unknown atomic operation method\n");
9323
return NULL;
9324
}
9325
classBlock = fej9->getClassFromSignature(className, classNameLen, comp->getCurrentMethod(), true);
9326
int32_t arrayFieldOffset = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock, "array", 5, fieldSig, fieldSigLen);
9327
9328
TR::MemoryReference *tempMR = TR::MemoryReference::createWithDisplacement(cg, valueReg, arrayFieldOffset, size);
9329
scratchReg = cg->allocateCollectedReferenceRegister();
9330
9331
if (TR::Compiler->om.compressObjectReferences())
9332
// read only 32 bits
9333
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, scratchReg,
9334
TR::MemoryReference::createWithDisplacement(cg, valueReg, arrayFieldOffset, 4));
9335
else
9336
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, scratchReg, TR::MemoryReference::createWithDisplacement(cg, valueReg, arrayFieldOffset, TR::Compiler->om.sizeofReferenceAddress()));
9337
9338
valueReg = scratchReg;
9339
fieldOffsetReg = cg->allocateRegister();
9340
numDeps += 2;
9341
generateShiftLeftImmediate(cg, node, fieldOffsetReg, indexReg, shiftAmount);
9342
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, fieldOffsetReg, fieldOffsetReg, fieldOffset);
9343
}
9344
9345
if (isUnsafe)
9346
{
9347
//right now not checking for ref, just doing long!
9348
if (isRefWrite)
9349
{
9350
}
9351
else
9352
{
9353
if (expValChild->getOpCode().isLoadConst() && expValChild->getRegister() == NULL)
9354
{
9355
if (size == 8)
9356
expValImm = expValChild->getLongInt();
9357
else
9358
expValImm = expValChild->getInt();
9359
if (expValImm >= LOWER_IMMED && expValImm <= UPPER_IMMED)
9360
isArgImm = true;
9361
}
9362
9363
if (!isArgImm)
9364
{
9365
expValReg = cg->evaluate(expValChild);
9366
numDeps++;
9367
}
9368
9369
newValReg = cg->evaluate(newValChild);
9370
numDeps++;
9371
}
9372
}
9373
9374
if (isCAS)
9375
{
9376
TR::LabelSymbol *rsvFailLabel;
9377
cndReg = cg->allocateRegister(TR_CCR);
9378
currentReg = cg->allocateRegister();
9379
numDeps += 2;
9380
startLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
9381
failLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
9382
doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
9383
9384
//allow spurious failures
9385
rsvFailLabel = isWeak ? failLabel : startLabel;
9386
9387
startLabel->setStartInternalControlFlow();
9388
9389
if (fieldOffsetReg == NULL)
9390
{
9391
numDeps++;
9392
fieldOffsetReg = cg->allocateRegister();
9393
loadConstant(cg, node, fieldOffset, fieldOffsetReg);
9394
}
9395
if (resultReg == NULL)
9396
{
9397
resultReg = fieldOffsetReg;
9398
}
9399
9400
if (!isWeak)
9401
generateInstruction(cg, TR::InstOpCode::lwsync, node);
9402
9403
generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);
9404
9405
generateTrg1MemInstruction(cg, size == 8 ? TR::InstOpCode::ldarx : TR::InstOpCode::lwarx, node, currentReg,
9406
TR::MemoryReference::createWithIndexReg(cg, valueReg, (fieldOffsetReg->getRegisterPair() ? fieldOffsetReg->getLowOrder() : fieldOffsetReg), size));
9407
9408
if (size == 8 && comp->target().is32Bit())
9409
{
9410
if (!isArgImm && expValReg->getRegisterPair())
9411
{
9412
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldimi, node, expValReg->getLowOrder(), expValReg->getHighOrder(), 32, CONSTANT64(0xFFFFFFFF00000000));
9413
expPair = true;
9414
numDeps++;
9415
}
9416
if (newValReg->getRegisterPair())
9417
{
9418
if (newValReg != expValReg)
9419
{
9420
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldimi, node, newValReg->getLowOrder(), newValReg->getHighOrder(), 32, CONSTANT64(0xFFFFFFFF00000000));
9421
}
9422
numDeps++;
9423
newPair = true;
9424
}
9425
}
9426
9427
if (!isArgImm && expComposedReg == NULL)
9428
{
9429
if (expPair)
9430
expComposedReg = expValReg->getLowOrder();
9431
else
9432
expComposedReg = expValReg != NULL ? expValReg : expRefReg;
9433
}
9434
if (newComposedReg == NULL)
9435
{
9436
if (newPair)
9437
newComposedReg = newValReg->getLowOrder();
9438
else
9439
newComposedReg = newValReg != NULL ? newValReg : newRefReg;
9440
}
9441
9442
if (isArgImm)
9443
{
9444
generateTrg1Src1ImmInstruction(cg, size == 8 ? TR::InstOpCode::cmpi8 : TR::InstOpCode::cmpi4, node, cndReg, currentReg, expValImm);
9445
}
9446
else
9447
{
9448
generateTrg1Src2Instruction(cg, size == 8 ? TR::InstOpCode::cmp8 : TR::InstOpCode::cmp4, node, cndReg, currentReg, expComposedReg);
9449
}
9450
9451
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, failLabel, cndReg);
9452
generateMemSrc1Instruction(cg, size == 8 ? TR::InstOpCode::stdcx_r : TR::InstOpCode::stwcx_r, node,
9453
TR::MemoryReference::createWithIndexReg(cg, valueReg, (fieldOffsetReg->getRegisterPair() ? fieldOffsetReg->getLowOrder() : fieldOffsetReg), size),
9454
newComposedReg);
9455
9456
/* Expect store to be successful, so this branch is usually not taken */
9457
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, rsvFailLabel, cndReg);
9458
9459
if (!isWeak)
9460
generateInstruction(cg, TR::InstOpCode::sync, node);
9461
9462
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1);
9463
generateLabelInstruction(cg, TR::InstOpCode::b, node, doneLabel);
9464
generateLabelInstruction(cg, TR::InstOpCode::label, node, failLabel);
9465
9466
if (!isWeak && size == 8 && comp->target().is32Bit())
9467
{
9468
/* store original current value conditionally
9469
* if it succeeds, then this was a true failure, if it
9470
* does not, it could have been corruption messing up the compare
9471
*/
9472
generateMemSrc1Instruction(cg, size == 8 ? TR::InstOpCode::stdcx_r : TR::InstOpCode::stwcx_r, node,
9473
TR::MemoryReference::createWithIndexReg(cg, valueReg, (fieldOffsetReg->getRegisterPair() ? fieldOffsetReg->getLowOrder() : fieldOffsetReg), size),
9474
currentReg);
9475
/* Expect store to be successful, so this branch is usually not taken */
9476
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, node, startLabel, cndReg);
9477
}
9478
9479
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 0);
9480
9481
}
9482
9483
TR::RegisterDependencyConditions *conditions;
9484
conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, numDeps, cg->trMemory());
9485
conditions->addPostCondition(valueReg, TR::RealRegister::NoReg);
9486
conditions->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0();
9487
conditions->addPostCondition(currentReg, TR::RealRegister::NoReg);
9488
9489
numDeps -= 2;
9490
if (fieldOffsetReg != NULL)
9491
{
9492
conditions->addPostCondition(fieldOffsetReg, TR::RealRegister::NoReg);
9493
numDeps--;
9494
}
9495
if (resultReg != fieldOffsetReg)
9496
{
9497
conditions->addPostCondition(resultReg, TR::RealRegister::NoReg);
9498
numDeps--;
9499
}
9500
if (objReg != valueReg)
9501
{
9502
conditions->addPostCondition(objReg, TR::RealRegister::NoReg);
9503
numDeps--;
9504
}
9505
if (isUnsafe)
9506
{
9507
if (isRefWrite)
9508
{
9509
conditions->addPostCondition(newRefReg, TR::RealRegister::NoReg);
9510
conditions->addPostCondition(expRefReg, TR::RealRegister::NoReg);
9511
numDeps -= 2;
9512
}
9513
else
9514
{
9515
if (newPair)
9516
{
9517
conditions->addPostCondition(newValReg->getHighOrder(), TR::RealRegister::NoReg);
9518
conditions->addPostCondition(newValReg->getLowOrder(), TR::RealRegister::NoReg);
9519
numDeps--;
9520
}
9521
else
9522
{
9523
conditions->addPostCondition(newValReg, TR::RealRegister::NoReg);
9524
}
9525
numDeps--;
9526
if (!isArgImm)
9527
{
9528
if (expPair)
9529
{
9530
conditions->addPostCondition(expValReg->getHighOrder(), TR::RealRegister::NoReg);
9531
conditions->addPostCondition(expValReg->getLowOrder(), TR::RealRegister::NoReg);
9532
numDeps--;
9533
}
9534
else
9535
{
9536
conditions->addPostCondition(expValReg, TR::RealRegister::NoReg);
9537
}
9538
numDeps--;
9539
}
9540
}
9541
}
9542
9543
conditions->addPostCondition(cndReg, TR::RealRegister::cr0);
9544
numDeps--;
9545
9546
doneLabel->setEndInternalControlFlow();
9547
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);
9548
9549
if (firstChild)
9550
cg->decReferenceCount(firstChild);
9551
cg->decReferenceCount(valueChild);
9552
cg->decReferenceCount(indexChild);
9553
cg->decReferenceCount(expValChild);
9554
cg->decReferenceCount(newValChild);
9555
cg->stopUsingRegister(cndReg);
9556
cg->stopUsingRegister(currentReg);
9557
node->setRegister(resultReg);
9558
9559
return resultReg;
9560
}
9561
9562
static TR::Register *compressStringEvaluator(TR::Node *node, TR::CodeGenerator *cg, bool japaneseMethod)
9563
{
9564
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());
9565
TR::Node *srcObjNode, *dstObjNode, *startNode, *lengthNode;
9566
TR::Register *srcObjReg = NULL, *dstObjReg = NULL, *lengthReg = NULL, *startReg = NULL;
9567
9568
srcObjNode = node->getChild(0);
9569
dstObjNode = node->getChild(1);
9570
startNode = node->getChild(2);
9571
lengthNode = node->getChild(3);
9572
9573
bool stopUsingCopyReg1, stopUsingCopyReg2, stopUsingCopyReg3, stopUsingCopyReg4;
9574
9575
stopUsingCopyReg1 = TR::TreeEvaluator::stopUsingCopyReg(srcObjNode, srcObjReg, cg);
9576
stopUsingCopyReg2 = TR::TreeEvaluator::stopUsingCopyReg(dstObjNode, dstObjReg, cg);
9577
stopUsingCopyReg3 = TR::TreeEvaluator::stopUsingCopyReg(startNode, startReg, cg);
9578
stopUsingCopyReg4 = TR::TreeEvaluator::stopUsingCopyReg(lengthNode, lengthReg, cg);
9579
9580
uintptr_t hdrSize = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();
9581
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, srcObjReg, srcObjReg, hdrSize);
9582
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, dstObjReg, dstObjReg, hdrSize);
9583
9584
TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(12, 12, cg->trMemory());
9585
TR::Register *cndRegister = cg->allocateRegister(TR_CCR);
9586
TR::Register *resultReg = cg->allocateRegister(TR_GPR);
9587
TR::addDependency(conditions, cndRegister, TR::RealRegister::cr0, TR_CCR, cg);
9588
TR::addDependency(conditions, lengthReg, TR::RealRegister::gr8, TR_GPR, cg);
9589
TR::addDependency(conditions, startReg, TR::RealRegister::gr7, TR_GPR, cg);
9590
TR::addDependency(conditions, srcObjReg, TR::RealRegister::gr9, TR_GPR, cg);
9591
TR::addDependency(conditions, dstObjReg, TR::RealRegister::gr10, TR_GPR, cg);
9592
9593
TR::addDependency(conditions, NULL, TR::RealRegister::gr0, TR_GPR, cg);
9594
TR::addDependency(conditions, NULL, TR::RealRegister::gr11, TR_GPR, cg);
9595
TR::addDependency(conditions, NULL, TR::RealRegister::gr6, TR_GPR, cg);
9596
TR::addDependency(conditions, NULL, TR::RealRegister::gr4, TR_GPR, cg);
9597
TR::addDependency(conditions, NULL, TR::RealRegister::gr5, TR_GPR, cg);
9598
TR::addDependency(conditions, NULL, TR::RealRegister::gr12, TR_GPR, cg);
9599
TR::addDependency(conditions, resultReg, TR::RealRegister::gr3, TR_GPR, cg);
9600
9601
if (japaneseMethod)
9602
TR::TreeEvaluator::generateHelperBranchAndLinkInstruction(TR_PPCcompressStringJ, node, conditions, cg);
9603
else
9604
TR::TreeEvaluator::generateHelperBranchAndLinkInstruction(TR_PPCcompressString, node, conditions, cg);
9605
9606
TR::Register* regs[5] =
9607
{
9608
lengthReg, startReg, srcObjReg, dstObjReg, resultReg
9609
};
9610
conditions->stopUsingDepRegs(cg, 5, regs);
9611
for (uint16_t i = 0; i < node->getNumChildren(); i++)
9612
cg->decReferenceCount(node->getChild(i));
9613
if (stopUsingCopyReg1)
9614
cg->stopUsingRegister(srcObjReg);
9615
if (stopUsingCopyReg2)
9616
cg->stopUsingRegister(dstObjReg);
9617
if (stopUsingCopyReg3)
9618
cg->stopUsingRegister(startReg);
9619
if (stopUsingCopyReg4)
9620
cg->stopUsingRegister(lengthReg);
9621
9622
node->setRegister(resultReg);
9623
9624
cg->machine()->setLinkRegisterKilled(true);
9625
cg->setHasCall();
9626
return (resultReg);
9627
}
9628
9629
static TR::Register *compressStringNoCheckEvaluator(TR::Node *node, TR::CodeGenerator *cg, bool japaneseMethod)
9630
{
9631
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());
9632
TR::Node *srcObjNode, *dstObjNode, *startNode, *lengthNode;
9633
TR::Register *srcObjReg = NULL, *dstObjReg = NULL, *lengthReg = NULL, *startReg = NULL;
9634
9635
srcObjNode = node->getChild(0);
9636
dstObjNode = node->getChild(1);
9637
startNode = node->getChild(2);
9638
lengthNode = node->getChild(3);
9639
9640
bool stopUsingCopyReg1, stopUsingCopyReg2, stopUsingCopyReg3, stopUsingCopyReg4;
9641
9642
stopUsingCopyReg1 = TR::TreeEvaluator::stopUsingCopyReg(srcObjNode, srcObjReg, cg);
9643
stopUsingCopyReg2 = TR::TreeEvaluator::stopUsingCopyReg(dstObjNode, dstObjReg, cg);
9644
stopUsingCopyReg3 = TR::TreeEvaluator::stopUsingCopyReg(startNode, startReg, cg);
9645
stopUsingCopyReg4 = TR::TreeEvaluator::stopUsingCopyReg(lengthNode, lengthReg, cg);
9646
9647
uintptr_t hdrSize = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();
9648
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, srcObjReg, srcObjReg, hdrSize);
9649
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, dstObjReg, dstObjReg, hdrSize);
9650
9651
int numOfRegs = japaneseMethod ? 11 : 12;
9652
TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(numOfRegs, numOfRegs, cg->trMemory());
9653
TR::Register *cndRegister = cg->allocateRegister(TR_CCR);
9654
TR::addDependency(conditions, cndRegister, TR::RealRegister::cr0, TR_CCR, cg);
9655
TR::addDependency(conditions, lengthReg, TR::RealRegister::gr8, TR_GPR, cg);
9656
TR::addDependency(conditions, startReg, TR::RealRegister::gr7, TR_GPR, cg);
9657
TR::addDependency(conditions, srcObjReg, TR::RealRegister::gr9, TR_GPR, cg);
9658
TR::addDependency(conditions, dstObjReg, TR::RealRegister::gr10, TR_GPR, cg);
9659
9660
TR::addDependency(conditions, NULL, TR::RealRegister::gr0, TR_GPR, cg);
9661
TR::addDependency(conditions, NULL, TR::RealRegister::gr11, TR_GPR, cg);
9662
TR::addDependency(conditions, NULL, TR::RealRegister::gr6, TR_GPR, cg);
9663
TR::addDependency(conditions, NULL, TR::RealRegister::gr4, TR_GPR, cg);
9664
TR::addDependency(conditions, NULL, TR::RealRegister::gr5, TR_GPR, cg);
9665
TR::addDependency(conditions, NULL, TR::RealRegister::gr3, TR_GPR, cg);
9666
if (!japaneseMethod)
9667
TR::addDependency(conditions, NULL, TR::RealRegister::gr12, TR_GPR, cg);
9668
9669
if (japaneseMethod)
9670
TR::TreeEvaluator::generateHelperBranchAndLinkInstruction(TR_PPCcompressStringNoCheckJ, node, conditions, cg);
9671
else
9672
TR::TreeEvaluator::generateHelperBranchAndLinkInstruction(TR_PPCcompressStringNoCheck, node, conditions, cg);
9673
9674
TR::Register* regs[4] =
9675
{
9676
lengthReg, startReg, srcObjReg, dstObjReg
9677
};
9678
conditions->stopUsingDepRegs(cg, 4, regs);
9679
for (uint16_t i = 0; i < node->getNumChildren(); i++)
9680
cg->decReferenceCount(node->getChild(i));
9681
if (stopUsingCopyReg1)
9682
cg->stopUsingRegister(srcObjReg);
9683
if (stopUsingCopyReg2)
9684
cg->stopUsingRegister(dstObjReg);
9685
if (stopUsingCopyReg3)
9686
cg->stopUsingRegister(startReg);
9687
if (stopUsingCopyReg4)
9688
cg->stopUsingRegister(lengthReg);
9689
9690
cg->machine()->setLinkRegisterKilled(true);
9691
cg->setHasCall();
9692
return NULL;
9693
}
9694
9695
static TR::Register *andORStringEvaluator(TR::Node *node, TR::CodeGenerator *cg)
9696
{
9697
TR_J9VMBase *fej9 = (TR_J9VMBase *) (cg->comp()->fe());
9698
TR::Node *srcObjNode, *startNode, *lengthNode;
9699
TR::Register *srcObjReg = NULL, *lengthReg = NULL, *startReg = NULL;
9700
9701
srcObjNode = node->getChild(0);
9702
startNode = node->getChild(1);
9703
lengthNode = node->getChild(2);
9704
9705
bool stopUsingCopyReg1, stopUsingCopyReg2, stopUsingCopyReg3;
9706
9707
stopUsingCopyReg1 = TR::TreeEvaluator::stopUsingCopyReg(srcObjNode, srcObjReg, cg);
9708
stopUsingCopyReg2 = TR::TreeEvaluator::stopUsingCopyReg(startNode, startReg, cg);
9709
stopUsingCopyReg3 = TR::TreeEvaluator::stopUsingCopyReg(lengthNode, lengthReg, cg);
9710
9711
uintptr_t hdrSize = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();
9712
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, srcObjReg, srcObjReg, hdrSize);
9713
9714
TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(8, 8, cg->trMemory());
9715
TR::Register *cndRegister = cg->allocateRegister(TR_CCR);
9716
TR::Register *resultReg = cg->allocateRegister(TR_GPR);
9717
TR::addDependency(conditions, cndRegister, TR::RealRegister::cr0, TR_CCR, cg);
9718
TR::addDependency(conditions, lengthReg, TR::RealRegister::gr8, TR_GPR, cg);
9719
TR::addDependency(conditions, startReg, TR::RealRegister::gr7, TR_GPR, cg);
9720
TR::addDependency(conditions, srcObjReg, TR::RealRegister::gr9, TR_GPR, cg);
9721
9722
TR::addDependency(conditions, NULL, TR::RealRegister::gr0, TR_GPR, cg);
9723
TR::addDependency(conditions, NULL, TR::RealRegister::gr4, TR_GPR, cg);
9724
TR::addDependency(conditions, NULL, TR::RealRegister::gr5, TR_GPR, cg);
9725
TR::addDependency(conditions, resultReg, TR::RealRegister::gr3, TR_GPR, cg);
9726
9727
TR::TreeEvaluator::generateHelperBranchAndLinkInstruction(TR_PPCandORString, node, conditions, cg);
9728
9729
TR::Register* regs[4] =
9730
{
9731
lengthReg, startReg, srcObjReg, resultReg
9732
};
9733
conditions->stopUsingDepRegs(cg, 4, regs);
9734
9735
for (uint16_t i = 0; i < node->getNumChildren(); i++)
9736
cg->decReferenceCount(node->getChild(i));
9737
if (stopUsingCopyReg1)
9738
cg->stopUsingRegister(srcObjReg);
9739
if (stopUsingCopyReg2)
9740
cg->stopUsingRegister(startReg);
9741
if (stopUsingCopyReg3)
9742
cg->stopUsingRegister(lengthReg);
9743
9744
node->setRegister(resultReg);
9745
9746
cg->machine()->setLinkRegisterKilled(true);
9747
cg->setHasCall();
9748
return (resultReg);
9749
}
9750
9751
static TR::Register *inlineConcurrentLinkedQueueTMOffer(TR::Node *node, TR::CodeGenerator *cg)
9752
{
9753
TR::Compilation *comp = cg->comp();
9754
TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());
9755
int32_t addressFieldSize = TR::Compiler->om.sizeofReferenceField();
9756
TR::InstOpCode::Mnemonic loadOpCode = (addressFieldSize == 8) ? TR::InstOpCode::ld : TR::InstOpCode::lwz;
9757
TR::InstOpCode::Mnemonic storeOpCode = (addressFieldSize == 8) ? TR::InstOpCode::std : TR::InstOpCode::stw;
9758
bool usesCompressedrefs = comp->useCompressedPointers();
9759
9760
// wrt bar
9761
auto gcMode = TR::Compiler->om.writeBarrierType();
9762
bool doWrtBar = (gcMode == gc_modron_wrtbar_satb || gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always
9763
|| TR::Options::getCmdLineOptions()->realTimeGC());
9764
bool doCrdMrk = ((gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_cardmark_incremental) && (!node->getOpCode().isWrtBar() || !node->isNonHeapObjectWrtBar()));
9765
9766
TR_OpaqueClassBlock * classBlock = NULL;
9767
classBlock = fej9->getClassFromSignature("Ljava/util/concurrent/ConcurrentLinkedQueue$Node;", 49, comp->getCurrentMethod(), true);
9768
int32_t offsetNext = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock, "next", 4, "Ljava/util/concurrent/ConcurrentLinkedQueue$Node;", 49);
9769
classBlock = fej9->getClassFromSignature("Ljava/util/concurrent/ConcurrentLinkedQueue;", 44, comp->getCurrentMethod(), true);
9770
int32_t offsetTail = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock, "tail", 4, "Ljava/util/concurrent/ConcurrentLinkedQueue$Node;", 49);
9771
9772
TR::Register * cndReg = cg->allocateRegister(TR_CCR);
9773
TR::Register * resultReg = cg->allocateRegister();
9774
TR::Register * objReg = cg->evaluate(node->getFirstChild());
9775
TR::Register * nReg = cg->evaluate(node->getSecondChild());
9776
TR::Register * pReg = cg->allocateRegister();
9777
TR::Register * qReg = cg->allocateRegister();
9778
TR::Register * retryCountReg = cg->allocateRegister();
9779
TR::Register * temp3Reg = NULL;
9780
TR::Register * temp4Reg = NULL;
9781
9782
TR::LabelSymbol * loopLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
9783
TR::LabelSymbol * insertLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
9784
TR::LabelSymbol * failureLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
9785
TR::LabelSymbol * returnLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
9786
TR::LabelSymbol * wrtbar1Donelabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
9787
9788
int numDeps = doWrtBar? 11 : 9; //two extra deps for space boundaries (used in wrtbar)
9789
9790
TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(numDeps, numDeps, cg->trMemory());
9791
9792
TR::addDependency(conditions, cndReg, TR::RealRegister::cr0, TR_CCR, cg);
9793
TR::addDependency(conditions, resultReg, TR::RealRegister::NoReg, TR_GPR, cg);
9794
TR::addDependency(conditions, objReg, TR::RealRegister::NoReg, TR_GPR, cg);
9795
TR::addDependency(conditions, pReg, TR::RealRegister::gr3, TR_GPR, cg); // dstReg for wrtbar
9796
TR::addDependency(conditions, qReg, TR::RealRegister::gr11, TR_GPR, cg); // temp1Reg for wrtbar
9797
TR::addDependency(conditions, retryCountReg, TR::RealRegister::NoReg, TR_GPR, cg); // temp2Reg for wrtbar
9798
TR::addDependency(conditions, nReg, TR::RealRegister::gr4, TR_GPR, cg); // srcReg for wrtbar
9799
9800
static char * disableTMOffer = feGetEnv("TR_DisableTMOffer");
9801
static char * debugTM = feGetEnv("TR_DebugTM");
9802
9803
/*
9804
* TM is not compatible with read barriers. If read barriers are required, TM is disabled.
9805
*/
9806
if (disableTMOffer || TR::Compiler->om.readBarrierType() != gc_modron_readbar_none)
9807
{
9808
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 3); // TM offer disabled
9809
generateLabelInstruction(cg, TR::InstOpCode::b, node, returnLabel);
9810
}
9811
9812
if (debugTM)
9813
{
9814
printf("\nTM: use TM CLQ.Offer in %s (%s)", comp->signature(), comp->getHotnessName(comp->getMethodHotness()));
9815
fflush (stdout);
9816
}
9817
9818
static const char *s = feGetEnv("TR_TMOfferRetry");
9819
static uint16_t TMOfferRetry = s ? atoi(s) : 7;
9820
9821
//#define CLQ_OFFER_RETRY 7
9822
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, retryCountReg, TMOfferRetry);
9823
9824
generateLabelInstruction(cg, TR::InstOpCode::label, node, loopLabel);
9825
9826
generateInstruction(cg, TR::InstOpCode::tbegin_r, node);
9827
9828
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, failureLabel, cndReg);
9829
9830
// ALG: p := this.tail
9831
generateTrg1MemInstruction(cg, loadOpCode, node, pReg, TR::MemoryReference::createWithDisplacement(cg, objReg, offsetTail, addressFieldSize));
9832
if (usesCompressedrefs)
9833
{
9834
genDecompressPointerWithTempReg(cg, node, pReg, resultReg, NULL, false); // p is not null
9835
}
9836
9837
// ALG: q := p.next
9838
generateTrg1MemInstruction(cg, loadOpCode, node, qReg, TR::MemoryReference::createWithDisplacement(cg, pReg, offsetNext, addressFieldSize));
9839
9840
// ALG: if q == null goto insertLabel
9841
generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, cndReg, qReg, 0);
9842
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, insertLabel, cndReg);
9843
9844
if (usesCompressedrefs)
9845
{
9846
genDecompressPointerWithTempReg(cg, node, qReg, resultReg, NULL, false); // q has been checked not null
9847
}
9848
9849
// ALG: p := q
9850
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, pReg, qReg);
9851
9852
// ALG: q := p.next
9853
generateTrg1MemInstruction(cg, loadOpCode, node, qReg, TR::MemoryReference::createWithDisplacement(cg, pReg, offsetNext, addressFieldSize));
9854
9855
// ALG: if q == null goto insertLabel
9856
generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, cndReg, qReg, 0);
9857
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, PPCOpProp_BranchLikely, node, insertLabel, cndReg);
9858
9859
// ALG: tend.
9860
generateInstruction(cg, TR::InstOpCode::tend_r, node);
9861
9862
// ALG: res := 1
9863
// cannot find tail
9864
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1);
9865
9866
// ALG: goto returnLabel
9867
generateLabelInstruction(cg, TR::InstOpCode::b, node, returnLabel);
9868
9869
// ALG: *** insert:
9870
generateLabelInstruction(cg, TR::InstOpCode::label, node, insertLabel);
9871
9872
// need uncompressed nReg for the wrtbar
9873
TR::Register *compressedReg = nReg;
9874
if (usesCompressedrefs)
9875
{
9876
compressedReg = genCompressPointerNonNull2RegsWithTempReg(cg, node, nReg, qReg, resultReg); //In Java code checkNotNull() already ensures n != null
9877
}
9878
// ALG: p.next := n
9879
generateMemSrc1Instruction(cg, storeOpCode, node, TR::MemoryReference::createWithDisplacement(cg, pReg, offsetNext, addressFieldSize), compressedReg);
9880
9881
// ALG: this.tail = n
9882
generateMemSrc1Instruction(cg, storeOpCode, node, TR::MemoryReference::createWithDisplacement(cg, objReg, offsetTail, addressFieldSize), compressedReg);
9883
9884
// ALG: tend
9885
generateInstruction(cg, TR::InstOpCode::tend_r, node);
9886
9887
// ALG: res := 0
9888
// TM success
9889
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 0);
9890
9891
if (doWrtBar)
9892
{
9893
if (doCrdMrk)
9894
{
9895
temp3Reg = cg->allocateRegister();
9896
temp4Reg = cg->allocateRegister();
9897
TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);
9898
TR::addDependency(conditions, temp4Reg, TR::RealRegister::NoReg, TR_GPR, cg);
9899
conditions->getPostConditions()->getRegisterDependency(5)->setExcludeGPR0(); //5=temp2Reg
9900
}
9901
9902
VMnonNullSrcWrtBarCardCheckEvaluator(node, nReg, pReg, cndReg, qReg, retryCountReg, temp3Reg, temp4Reg, wrtbar1Donelabel, conditions, false, cg, false);
9903
// ALG: *** wrtbar1Donelabel
9904
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, wrtbar1Donelabel, conditions);
9905
9906
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, pReg, objReg);
9907
9908
VMnonNullSrcWrtBarCardCheckEvaluator(node, nReg, pReg, cndReg, qReg, retryCountReg, temp3Reg, temp4Reg, returnLabel, conditions, false, cg, false);
9909
9910
}
9911
else if (doCrdMrk)
9912
{
9913
temp3Reg = cg->allocateRegister();
9914
TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);
9915
conditions->getPostConditions()->getRegisterDependency(3)->setExcludeGPR0(); //3=dstReg
9916
conditions->getPostConditions()->getRegisterDependency(4)->setExcludeGPR0(); //4=temp1Reg
9917
9918
VMCardCheckEvaluator(node, pReg, cndReg, qReg, retryCountReg, temp3Reg, conditions, cg);
9919
9920
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, pReg, objReg);
9921
9922
VMCardCheckEvaluator(node, pReg, cndReg, qReg, retryCountReg, temp3Reg, conditions, cg);
9923
}
9924
9925
// ALG: goto returnLabel
9926
generateLabelInstruction(cg, TR::InstOpCode::b, node, returnLabel);
9927
9928
// ALG: *** failureLabel
9929
generateLabelInstruction(cg, TR::InstOpCode::label, node, failureLabel);
9930
//generateDepLabelInstruction(cg, TR::InstOpCode::label, node, failureLabel, conditions);
9931
9932
// retryCount-=1
9933
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addic_r, node, retryCountReg, retryCountReg, -1);
9934
9935
// ALG: goto loopLabel
9936
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, loopLabel, cndReg);
9937
9938
// ALG: res := 2
9939
// exceeds retry count
9940
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 2);
9941
9942
// ALG: *** return
9943
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, returnLabel, conditions);
9944
9945
// wrtbar or after TM success earlier
9946
9947
cg->decReferenceCount(node->getFirstChild());
9948
cg->decReferenceCount(node->getSecondChild());
9949
cg->stopUsingRegister(pReg);
9950
cg->stopUsingRegister(qReg);
9951
cg->stopUsingRegister(retryCountReg);
9952
cg->stopUsingRegister(cndReg);
9953
if (temp3Reg != NULL)
9954
cg->stopUsingRegister(temp3Reg);
9955
if (temp4Reg != NULL)
9956
cg->stopUsingRegister(temp4Reg);
9957
9958
node->setRegister(resultReg);
9959
resultReg->setContainsCollectedReference();
9960
return resultReg;
9961
}
9962
9963
static TR::Register *inlineConcurrentLinkedQueueTMPoll(TR::Node *node, TR::CodeGenerator *cg)
9964
{
9965
TR::Compilation *comp = cg->comp();
9966
TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());
9967
int32_t addressFieldSize = TR::Compiler->om.sizeofReferenceField();
9968
TR::InstOpCode::Mnemonic loadOpCode = (addressFieldSize == 8) ? TR::InstOpCode::ld : TR::InstOpCode::lwz;
9969
TR::InstOpCode::Mnemonic storeOpCode = (addressFieldSize == 8) ? TR::InstOpCode::std : TR::InstOpCode::stw;
9970
bool usesCompressedrefs = comp->useCompressedPointers();
9971
9972
TR_OpaqueClassBlock *classBlock = fej9->getClassFromSignature("Ljava/util/concurrent/ConcurrentLinkedQueue;", 44, comp->getCurrentMethod(), true);
9973
int32_t offsetHead = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock, "head", 4, "Ljava/util/concurrent/ConcurrentLinkedQueue$Node;", 49);
9974
classBlock = fej9->getClassFromSignature("Ljava/util/concurrent/ConcurrentLinkedQueue$Node;", 49, comp->getCurrentMethod(), true);
9975
int32_t offsetNext = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock, "next", 4, "Ljava/util/concurrent/ConcurrentLinkedQueue$Node;", 49);
9976
int32_t offsetItem = fej9->getObjectHeaderSizeInBytes() + fej9->getInstanceFieldOffset(classBlock, "item", 4, "Ljava/lang/Object;", 18);
9977
9978
TR::Register * objReg = cg->evaluate(node->getFirstChild());
9979
TR::Register * cndReg = cg->allocateRegister(TR_CCR);
9980
TR::Register * resultReg = cg->allocateRegister();
9981
TR::Register * nullReg = cg->allocateRegister();
9982
TR::Register * pReg = cg->allocateRegister();
9983
TR::Register * qReg = cg->allocateRegister();
9984
TR::Register * temp3Reg = cg->allocateRegister();
9985
TR::Register * temp4Reg = NULL;
9986
9987
TR::LabelSymbol * tendLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
9988
TR::LabelSymbol * returnLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
9989
TR::LabelSymbol * failureLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
9990
9991
TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(8, 8, cg->trMemory());
9992
9993
TR::addDependency(conditions, cndReg, TR::RealRegister::cr0, TR_CCR, cg);
9994
TR::addDependency(conditions, resultReg, TR::RealRegister::NoReg, TR_GPR, cg);
9995
TR::addDependency(conditions, objReg, TR::RealRegister::gr3, TR_GPR, cg); // dstReg for wrtbar
9996
TR::addDependency(conditions, nullReg, TR::RealRegister::gr11, TR_GPR, cg); // temp1Reg for wrtbar
9997
TR::addDependency(conditions, pReg, TR::RealRegister::NoReg, TR_GPR, cg); // temp2Reg for wrtbar
9998
TR::addDependency(conditions, qReg, TR::RealRegister::gr4, TR_GPR, cg); // srcReg for wrtbar
9999
TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);
10000
10001
static char * disableTMPoll = feGetEnv("TR_DisableTMPoll");
10002
static char * debugTM = feGetEnv("TR_DebugTM");
10003
10004
/*
10005
* TM is not compatible with read barriers. If read barriers are required, TM is disabled.
10006
*/
10007
if (disableTMPoll || TR::Compiler->om.readBarrierType() != gc_modron_readbar_none)
10008
{
10009
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 0); // BEFORE WAS 0
10010
generateLabelInstruction(cg, TR::InstOpCode::b, node, returnLabel);
10011
}
10012
10013
if (debugTM)
10014
{
10015
printf("\nTM: use TM CLQ.Poll in %s (%s)", comp->signature(), comp->getHotnessName(comp->getMethodHotness()));
10016
fflush (stdout);
10017
}
10018
10019
generateInstruction(cg, TR::InstOpCode::tbegin_r, node);
10020
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, failureLabel, cndReg);
10021
10022
// ALG: p := this.head
10023
generateTrg1MemInstruction(cg, loadOpCode, node, temp3Reg, TR::MemoryReference::createWithDisplacement(cg, objReg, offsetHead, addressFieldSize));
10024
TR::Register *decompressedP = temp3Reg;
10025
if (usesCompressedrefs)
10026
{
10027
decompressedP = genDecompressPointerNonNull2RegsWithTempReg(cg, node, temp3Reg, pReg, qReg);
10028
}
10029
10030
// ALG: res := p.item
10031
generateTrg1MemInstruction(cg, loadOpCode, node, resultReg, TR::MemoryReference::createWithDisplacement(cg, decompressedP, offsetItem, addressFieldSize));
10032
if (usesCompressedrefs)
10033
{
10034
genDecompressPointerWithTempReg(cg, node, resultReg, qReg, cndReg); // NOTE: res could be null
10035
}
10036
10037
// ALG: q := p.next
10038
generateTrg1MemInstruction(cg, loadOpCode, node, qReg, TR::MemoryReference::createWithDisplacement(cg, decompressedP, offsetNext, addressFieldSize));
10039
10040
// ALG: p.item := null
10041
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, nullReg, 0);
10042
10043
generateMemSrc1Instruction(cg, storeOpCode, node, TR::MemoryReference::createWithDisplacement(cg, decompressedP, offsetItem, addressFieldSize), nullReg);
10044
10045
// ALG: if q == null goto tendLabel
10046
generateTrg1Src1ImmInstruction(cg,TR::InstOpCode::Op_cmpli, node, cndReg, qReg, 0);
10047
10048
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, tendLabel, cndReg);
10049
10050
// ALG: this.head = q
10051
// qReg is still compressed, use it to store
10052
generateMemSrc1Instruction(cg, storeOpCode, node, TR::MemoryReference::createWithDisplacement(cg, objReg, offsetHead, addressFieldSize), qReg);
10053
10054
if (usesCompressedrefs)
10055
{
10056
genDecompressPointerWithTempReg(cg, node, qReg, nullReg, NULL, false); // qReg is not null
10057
}
10058
10059
// ALG: p.next := p
10060
generateMemSrc1Instruction(cg, storeOpCode, node, TR::MemoryReference::createWithDisplacement(cg, decompressedP, offsetNext, addressFieldSize), temp3Reg);
10061
10062
// ALG: tend
10063
generateInstruction(cg, TR::InstOpCode::tend_r, node);
10064
10065
// WrtBar for this.head = q
10066
auto gcMode = TR::Compiler->om.writeBarrierType();
10067
bool doWrtBar = (gcMode == gc_modron_wrtbar_satb || gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always
10068
|| comp->getOptions()->realTimeGC());
10069
bool doCrdMrk = ((gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_cardmark_incremental) && (!node->getOpCode().isWrtBar() || !node->isNonHeapObjectWrtBar()));
10070
if (doWrtBar)
10071
{
10072
if (doCrdMrk)
10073
{
10074
temp4Reg = cg->allocateRegister();
10075
TR::addDependency(conditions, temp4Reg, TR::RealRegister::NoReg, TR_GPR, cg);
10076
conditions->getPostConditions()->getRegisterDependency(4)->setExcludeGPR0(); //4=temp2Reg
10077
}
10078
10079
VMnonNullSrcWrtBarCardCheckEvaluator(node, qReg, objReg, cndReg, nullReg, pReg, temp3Reg, temp4Reg, returnLabel, conditions, false, cg, false);
10080
}
10081
else if (doCrdMrk)
10082
{
10083
conditions->getPostConditions()->getRegisterDependency(2)->setExcludeGPR0(); //2=dstReg
10084
conditions->getPostConditions()->getRegisterDependency(3)->setExcludeGPR0(); //3=temp1Reg
10085
10086
VMCardCheckEvaluator(node, objReg, cndReg, nullReg, pReg, temp3Reg, conditions, cg);
10087
}
10088
10089
// ALG: goto returnLabel
10090
generateLabelInstruction(cg, TR::InstOpCode::b, node, returnLabel);
10091
10092
// ALG:**** tendLabel:
10093
generateLabelInstruction(cg, TR::InstOpCode::label, node, tendLabel);
10094
10095
// ALG: tend
10096
generateInstruction(cg, TR::InstOpCode::tend_r, node);
10097
10098
// ALG: goto returnLabel
10099
generateLabelInstruction(cg, TR::InstOpCode::b, node, returnLabel);
10100
10101
// ALG: *** failureLabel
10102
generateLabelInstruction(cg, TR::InstOpCode::label, node, failureLabel);
10103
// resultReg := 0
10104
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 0);
10105
10106
// ALG: *** returnLabel
10107
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, returnLabel, conditions);
10108
10109
// wrtbar if result is non-null
10110
10111
cg->decReferenceCount(node->getFirstChild());
10112
cg->stopUsingRegister(nullReg);
10113
cg->stopUsingRegister(pReg);
10114
cg->stopUsingRegister(qReg);
10115
cg->stopUsingRegister(cndReg);
10116
if (temp3Reg != NULL)
10117
cg->stopUsingRegister(temp3Reg);
10118
if (temp4Reg != NULL)
10119
cg->stopUsingRegister(temp4Reg);
10120
10121
node->setRegister(resultReg);
10122
resultReg->setContainsCollectedReference();
10123
return resultReg;
10124
}
10125
10126
#if defined(AIXPPC)
10127
static TR::Register *dangerousGetCPU(
10128
TR::Node *node,
10129
TR::CodeGenerator *cg)
10130
{
10131
// This is a bad idea that works most of the time.
10132
// We don't bother with ANY of the usual native method protocol(!)
10133
// But we do adjust r1 to be way out of the way and then call
10134
// "mycpu" which is buried deep in the kernel
10135
10136
TR::Register *retReg = cg->allocateRegister();
10137
TR::Register *gr1 = cg->allocateRegister();
10138
TR::Register *gr2 = cg->allocateRegister();
10139
TR::Register *tmpReg = cg->allocateRegister();
10140
TR::RegisterDependencyConditions *dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(4, 4, cg->trMemory());
10141
TR::Compilation *comp = cg->comp();
10142
TR::addDependency(dependencies, retReg, TR::RealRegister::gr3, TR_GPR, cg);
10143
TR::addDependency(dependencies, gr1, TR::RealRegister::gr1, TR_GPR, cg);
10144
TR::addDependency(dependencies, gr2, TR::RealRegister::gr2, TR_GPR, cg);
10145
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, gr1, gr1, -256);
10146
generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node,
10147
TR::MemoryReference::createWithDisplacement(cg, gr1, 0x14, TR::Compiler->om.sizeofReferenceAddress()),
10148
gr2);
10149
intptr_t xx[3];
10150
xx[0] = ((intptr_t *)(void *)&mycpu)[0];
10151
xx[1] = ((intptr_t *)(void *)&mycpu)[1];
10152
xx[2] = ((intptr_t *)(void *)&mycpu)[2];
10153
loadAddressConstant(cg, comp->compileRelocatableCode(), node, xx[0], tmpReg);
10154
loadAddressConstant(cg, comp->compileRelocatableCode(), node, xx[1], gr2);
10155
generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, tmpReg);
10156
generateInstruction(cg, TR::InstOpCode::bctrl, node);
10157
10158
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, gr2,
10159
TR::MemoryReference::createWithDisplacement(cg, gr1, 0x14, TR::Compiler->om.sizeofReferenceAddress()));
10160
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, gr1, gr1, 256);
10161
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, TR::LabelSymbol::create(cg->trHeapMemory(),cg), dependencies);
10162
cg->stopUsingRegister(gr1);
10163
cg->stopUsingRegister(gr2);
10164
cg->stopUsingRegister(tmpReg);
10165
node->setRegister(retReg);
10166
cg->machine()->setLinkRegisterKilled(true);
10167
return retReg;
10168
}
10169
#else
10170
static TR::Register *dangerousGetCPU(TR::Node *node, TR::CodeGenerator *cg)
10171
{
10172
return NULL;
10173
}
10174
#endif
10175
10176
static TR::Register *inlineFixedTrg1Src1(TR::Node *node, TR::InstOpCode::Mnemonic op, TR::CodeGenerator *cg)
10177
{
10178
TR_ASSERT(node->getNumChildren() == 1, "Wrong number of children in inlineFixedTrg1Src1");
10179
10180
TR::Node *firstChild = node->getFirstChild();
10181
TR::Register *srcRegister = cg->evaluate(firstChild);
10182
TR::Register *targetRegister = cg->allocateRegister();
10183
10184
generateTrg1Src1Instruction(cg, op, node, targetRegister, srcRegister);
10185
10186
node->setRegister(targetRegister);
10187
cg->decReferenceCount(firstChild);
10188
10189
return targetRegister;
10190
}
10191
10192
static TR::Register *inlineLongNumberOfTrailingZeros(TR::Node *node, TR::CodeGenerator *cg)
10193
{
10194
TR_ASSERT(node->getNumChildren() == 1, "Wrong number of children in inlineLongNumberOfTrailingZeros");
10195
10196
TR::Node *firstChild = node->getFirstChild();
10197
TR::Register *srcRegister = cg->evaluate(firstChild);
10198
TR::Register *targetRegister = cg->allocateRegister();
10199
TR::Register *tempRegister = cg->allocateRegister();
10200
TR::Register *maskRegister = cg->allocateRegister();
10201
10202
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addic, node, tempRegister, srcRegister->getLowOrder(), -1);
10203
generateTrg1Src1Instruction(cg, TR::InstOpCode::addme, node, targetRegister, srcRegister->getHighOrder());
10204
generateTrg1Src2Instruction(cg, TR::InstOpCode::andc, node, tempRegister, tempRegister, srcRegister->getLowOrder());
10205
generateTrg1Src2Instruction(cg, TR::InstOpCode::andc, node, targetRegister, targetRegister, srcRegister->getHighOrder());
10206
generateTrg1Src1Instruction(cg, TR::InstOpCode::cntlzw, node, targetRegister, targetRegister);
10207
generateTrg1Src1Instruction(cg, TR::InstOpCode::cntlzw, node, tempRegister, tempRegister);
10208
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, maskRegister, targetRegister, 27, 0x1);
10209
generateTrg1Src1Instruction(cg, TR::InstOpCode::neg, node, maskRegister, maskRegister);
10210
generateTrg1Src2Instruction(cg, TR::InstOpCode::AND, node, tempRegister, tempRegister, maskRegister);
10211
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, targetRegister, targetRegister, tempRegister);
10212
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::subfic, node, targetRegister, targetRegister, 64);
10213
10214
cg->stopUsingRegister(tempRegister);
10215
cg->stopUsingRegister(maskRegister);
10216
10217
node->setRegister(targetRegister);
10218
cg->decReferenceCount(firstChild);
10219
10220
return targetRegister;
10221
}
10222
10223
static TR::Register *inlineIsAssignableFrom(TR::Node *node, TR::CodeGenerator *cg)
10224
{
10225
TR::Compilation *comp = cg->comp();
10226
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());
10227
TR::Node *receiverNode = node->getFirstChild();
10228
TR::Node *parmNode = node->getSecondChild();
10229
10230
// If the receiver class is known at compile-time and the receiver and parm classes aren't the same,
10231
// we can check if the receiver is a super class of the parm class
10232
// Look for:
10233
// icall java/lang/Class.isAssignableFrom(Ljava/lang/Class;)Z
10234
// aloadi <javaLangClassFromClass>
10235
// loadaddr receiverj9class
10236
int32_t receiverClassDepth = -1;
10237
if (receiverNode->getOpCodeValue() == TR::aloadi &&
10238
receiverNode->getSymbolReference() == comp->getSymRefTab()->findJavaLangClassFromClassSymbolRef() &&
10239
receiverNode->getFirstChild()->getOpCodeValue() == TR::loadaddr)
10240
{
10241
TR::Node *receiverJ9ClassNode = receiverNode->getFirstChild();
10242
TR::SymbolReference *receiverJ9ClassSymRef = receiverJ9ClassNode->getSymbolReference();
10243
if (receiverJ9ClassSymRef && !receiverJ9ClassSymRef->isUnresolved())
10244
{
10245
TR::StaticSymbol *receiverJ9ClassSym = receiverJ9ClassSymRef->getSymbol()->getStaticSymbol();
10246
if (receiverJ9ClassSym)
10247
{
10248
TR_OpaqueClassBlock *receiverJ9ClassPtr = (TR_OpaqueClassBlock *)receiverJ9ClassSym->getStaticAddress();
10249
if (receiverJ9ClassPtr)
10250
{
10251
receiverClassDepth = (int32_t)TR::Compiler->cls.classDepthOf(receiverJ9ClassPtr);
10252
if (receiverClassDepth >= 0)
10253
{
10254
static bool disable = feGetEnv("TR_disableInlineIsAssignableFromSuperTest") != NULL;
10255
if (disable)
10256
receiverClassDepth = -1;
10257
}
10258
}
10259
}
10260
}
10261
}
10262
10263
TR_PPCScratchRegisterManager *srm = cg->generateScratchRegisterManager();
10264
TR::Register *receiverReg = cg->evaluate(node->getFirstChild());
10265
TR::Register *parmReg = cg->evaluate(node->getSecondChild());
10266
TR::Register *resultReg = cg->allocateRegister();
10267
TR::LabelSymbol *outlinedCallLabel = generateLabelSymbol(cg);
10268
TR::LabelSymbol *returnTrueLabel = generateLabelSymbol(cg);
10269
TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);
10270
10271
doneLabel->setEndInternalControlFlow();
10272
10273
// We don't want this guy to be live across the call to isAssignableFrom in the outlined section
10274
// because the CR reg will have to be spilled/restored.
10275
// Instead, we allocate it outside the srm and don't bother putting it in the dependencies on doneLabel.
10276
// For correctness we could free all CRs in the post conditions of doneLabel, but currently CRs are
10277
// never live outside of the evaluator they were created in so it's not a concern.
10278
TR::Register *condReg = cg->allocateRegister(TR_CCR);
10279
10280
// This is fine since we don't use any scratch regs after writing to the result reg
10281
srm->donateScratchRegister(resultReg);
10282
10283
// If either the receiver or the parm is null, bail out
10284
TR::Register *nullTestReg = srm->findOrCreateScratchRegister();
10285
if (!receiverNode->isNonNull())
10286
{
10287
genNullTest(node, receiverReg, condReg, nullTestReg, NULL, cg);
10288
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, outlinedCallLabel, condReg);
10289
}
10290
if (!parmNode->isNonNull())
10291
{
10292
genNullTest(node, parmReg, condReg, nullTestReg, NULL, cg);
10293
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, outlinedCallLabel, condReg);
10294
}
10295
srm->reclaimScratchRegister(nullTestReg);
10296
10297
// Compare receiver and parm
10298
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, receiverReg, parmReg);
10299
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, returnTrueLabel, condReg);
10300
10301
// Compare receiver and parm classes
10302
TR::Register *receiverJ9ClassReg = srm->findOrCreateScratchRegister();
10303
TR::Register *parmJ9ClassReg = srm->findOrCreateScratchRegister();
10304
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, receiverJ9ClassReg,
10305
TR::MemoryReference::createWithDisplacement(cg, receiverReg, fej9->getOffsetOfClassFromJavaLangClassField(), TR::Compiler->om.sizeofReferenceAddress()));
10306
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, parmJ9ClassReg,
10307
TR::MemoryReference::createWithDisplacement(cg, parmReg, fej9->getOffsetOfClassFromJavaLangClassField(), TR::Compiler->om.sizeofReferenceAddress()));
10308
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, receiverJ9ClassReg, parmJ9ClassReg);
10309
10310
TR::Register *scratch1Reg = NULL;
10311
if (receiverClassDepth >= 0)
10312
{
10313
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, returnTrueLabel, condReg);
10314
10315
scratch1Reg = srm->findOrCreateScratchRegister();
10316
TR::Register *scratch2Reg = srm->findOrCreateScratchRegister();
10317
10318
genTestIsSuper(node, parmJ9ClassReg, receiverJ9ClassReg, condReg, scratch1Reg, scratch2Reg, receiverClassDepth, outlinedCallLabel, NULL, cg);
10319
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, outlinedCallLabel, condReg);
10320
10321
srm->reclaimScratchRegister(scratch1Reg);
10322
srm->reclaimScratchRegister(scratch2Reg);
10323
}
10324
else
10325
{
10326
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, outlinedCallLabel, condReg);
10327
}
10328
10329
srm->reclaimScratchRegister(receiverJ9ClassReg);
10330
srm->reclaimScratchRegister(parmJ9ClassReg);
10331
generateLabelInstruction(cg, TR::InstOpCode::label, node, returnTrueLabel);
10332
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1);
10333
10334
TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 2 + srm->numAvailableRegisters(), cg->trMemory());
10335
deps->addPostCondition(receiverReg, TR::RealRegister::NoReg, UsesDependentRegister | ExcludeGPR0InAssigner);
10336
deps->addPostCondition(parmReg, TR::RealRegister::NoReg, UsesDependentRegister | ExcludeGPR0InAssigner);
10337
srm->addScratchRegistersToDependencyList(deps);
10338
// Make sure these two (added to the deps by the srm) have !gr0, since we use them as base regs
10339
deps->setPostDependencyExcludeGPR0(receiverJ9ClassReg);
10340
if (scratch1Reg)
10341
deps->setPostDependencyExcludeGPR0(scratch1Reg);
10342
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, deps);
10343
10344
TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory()) TR_PPCOutOfLineCodeSection(node, TR::icall, resultReg, outlinedCallLabel, doneLabel, cg);
10345
cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);
10346
10347
node->setRegister(resultReg);
10348
cg->decReferenceCount(node->getFirstChild());
10349
cg->decReferenceCount(node->getSecondChild());
10350
srm->stopUsingRegisters();
10351
cg->stopUsingRegister(condReg);
10352
10353
return resultReg;
10354
}
10355
10356
static TR::Register *inlineStringHashcode(TR::Node *node, TR::CodeGenerator *cg)
10357
{
10358
TR::Compilation *comp = cg->comp();
10359
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());
10360
bool isLE = comp->target().cpu.isLittleEndian();
10361
10362
TR::Node *valueNode = node->getFirstChild();
10363
TR::Node *offsetNode = node->getSecondChild();
10364
TR::Node *countNode = node->getThirdChild();
10365
10366
TR::Register *valueReg = cg->gprClobberEvaluate(valueNode);
10367
TR::Register *endReg = cg->gprClobberEvaluate(offsetNode);
10368
TR::Register *vendReg = cg->gprClobberEvaluate(countNode);
10369
TR::Register *hashReg = cg->allocateRegister();
10370
TR::Register *tempReg = cg->allocateRegister();
10371
TR::Register *constant0Reg = cg->allocateRegister();
10372
TR::Register *multiplierAddrReg = cg->allocateRegister();
10373
TR::Register *condReg = cg->allocateRegister(TR_CCR);
10374
10375
TR::Register *multiplierReg = cg->allocateRegister(TR_VRF);
10376
TR::Register *high4Reg = cg->allocateRegister(TR_VRF);
10377
TR::Register *low4Reg = cg->allocateRegister(TR_VRF);
10378
TR::Register *vtmp1Reg = cg->allocateRegister(TR_VRF);
10379
TR::Register *vtmp2Reg = cg->allocateRegister(TR_VRF);
10380
TR::Register *vconstant0Reg = cg->allocateRegister(TR_VRF);
10381
TR::Register *vconstantNegReg = cg->allocateRegister(TR_VRF);
10382
TR::Register *vunpackMaskReg = cg->allocateRegister(TR_VRF);
10383
10384
TR::LabelSymbol *serialLabel = generateLabelSymbol(cg);
10385
TR::LabelSymbol *VSXLabel = generateLabelSymbol(cg);
10386
TR::LabelSymbol *POSTVSXLabel = generateLabelSymbol(cg);
10387
TR::LabelSymbol *endLabel = generateLabelSymbol(cg);
10388
10389
// Skip header of the array
10390
// v = v + offset<<1
10391
// end = v + count<<1
10392
// hash = 0
10393
// temp = 0
10394
intptr_t hdrSize = TR::Compiler->om.contiguousArrayHeaderSizeInBytes();
10395
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, valueReg, valueReg, hdrSize);
10396
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, endReg, endReg, endReg);
10397
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, valueReg, valueReg, endReg);
10398
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, vendReg, vendReg, vendReg);
10399
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, endReg, valueReg, vendReg);
10400
generateTrg1Src2Instruction(cg, TR::InstOpCode::XOR, node, hashReg, hashReg, hashReg);
10401
generateTrg1Src2Instruction(cg, TR::InstOpCode::XOR, node, tempReg, tempReg, tempReg);
10402
loadConstant(cg, node, 0x0, constant0Reg);
10403
10404
// if count<<1 < 16 goto serial
10405
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, condReg, vendReg, 0x10);
10406
generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, serialLabel, condReg);
10407
10408
// load multiplier, clear high4 low4
10409
static uint32_t multiplierVectors_be[12] = {0x94446F01, 0x94446F01, 0x94446F01, 0x94446F01, 0x67E12CDF, 887503681, 28629151, 923521, 29791, 961, 31, 1};
10410
static uint32_t multiplierVectors_le[12] = {0x94446F01, 0x94446F01, 0x94446F01, 0x94446F01, 1, 31, 961, 29791, 923521, 28629151, 887503681, 0x67E12CDF};
10411
10412
if (isLE){
10413
loadAddressConstant(cg, false, node, (intptr_t)multiplierVectors_le, multiplierAddrReg);
10414
}else{
10415
loadAddressConstant(cg, false, node, (intptr_t)multiplierVectors_be, multiplierAddrReg);
10416
}
10417
generateTrg1MemInstruction(cg, TR::InstOpCode::lxvw4x, node, multiplierReg, TR::MemoryReference::createWithIndexReg(cg, multiplierAddrReg, constant0Reg, 16));
10418
generateTrg1Src2Instruction(cg, TR::InstOpCode::vxor, node, high4Reg, high4Reg, high4Reg);
10419
generateTrg1Src2Instruction(cg, TR::InstOpCode::vxor, node, low4Reg, low4Reg, low4Reg);
10420
generateTrg1Src2Instruction(cg, TR::InstOpCode::vxor, node, vconstant0Reg, vconstant0Reg, vconstant0Reg);
10421
generateTrg1Src2Instruction(cg, TR::InstOpCode::vnor, node, vconstantNegReg, vconstant0Reg, vconstant0Reg);
10422
generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::vsldoi, node, vunpackMaskReg, vconstant0Reg, vconstantNegReg, 2);
10423
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::vspltw, node, vunpackMaskReg, vunpackMaskReg, 3);
10424
10425
// vend = end & (~0xf)
10426
// if v is 16byte aligned goto VSX_LOOP
10427
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tempReg, 0xFFFFFFFFFFFFFFF0);
10428
generateTrg1Src2Instruction(cg, TR::InstOpCode::AND, node, vendReg, endReg, tempReg);
10429
loadConstant(cg, node, 0xF, tempReg);
10430
generateTrg1Src2Instruction(cg, TR::InstOpCode::AND, node, tempReg, valueReg, tempReg);
10431
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, condReg, tempReg, 0x0);
10432
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, VSXLabel, condReg);
10433
10434
// The reason we don't do VSX loop directly is we want to avoid loading unaligned data and deal it with vperm.
10435
// Instead, we load the first unaligned part, let VSX handle the rest aligned part.
10436
// load unaligned v, mask out unwanted part
10437
// for example, if value = 0x12345, we mask out 0x12340~0x12344, keep 0x12345~0x1234F
10438
generateTrg1MemInstruction(cg, TR::InstOpCode::lvx, node, vtmp1Reg, TR::MemoryReference::createWithIndexReg(cg, valueReg, constant0Reg, 16));
10439
loadConstant(cg, node, 0xF, tempReg);
10440
generateTrg1Src2Instruction(cg, TR::InstOpCode::AND, node, tempReg, valueReg, tempReg);
10441
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, tempReg, tempReg, 3, 0xFFFFFFFFFFFFFFF8);
10442
generateTrg1Src1Instruction(cg, TR::InstOpCode::mtvsrd, node, vtmp2Reg, tempReg);
10443
generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::vsldoi, node, vtmp2Reg, vconstant0Reg, vtmp2Reg, 8);
10444
if (isLE) {
10445
generateTrg1Src2Instruction(cg, TR::InstOpCode::vslo, node, vtmp2Reg, vconstantNegReg, vtmp2Reg);
10446
} else {
10447
generateTrg1Src2Instruction(cg, TR::InstOpCode::vsro, node, vtmp2Reg, vconstantNegReg, vtmp2Reg);
10448
}
10449
generateTrg1Src2Instruction(cg, TR::InstOpCode::vand, node, vtmp1Reg, vtmp1Reg, vtmp2Reg);
10450
10451
// unpack masked v to high4 low4
10452
generateTrg1Src1Instruction(cg, TR::InstOpCode::vupkhsh, node, high4Reg, vtmp1Reg);
10453
generateTrg1Src2Instruction(cg, TR::InstOpCode::vand, node, high4Reg, high4Reg, vunpackMaskReg);
10454
generateTrg1Src1Instruction(cg, TR::InstOpCode::vupklsh, node, low4Reg, vtmp1Reg);
10455
generateTrg1Src2Instruction(cg, TR::InstOpCode::vand, node, low4Reg, low4Reg, vunpackMaskReg);
10456
10457
// advance v to next aligned pointer
10458
// if v >= vend goto POST_VSX
10459
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, valueReg, valueReg, 0xF);
10460
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tempReg, 0xFFFFFFFFFFFFFFF0);
10461
generateTrg1Src2Instruction(cg, TR::InstOpCode::AND, node, valueReg, valueReg, tempReg);
10462
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp8, node, condReg, valueReg, vendReg);
10463
generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, POSTVSXLabel, condReg);
10464
10465
//VSX_LOOP:
10466
//load v (here v must be aligned)
10467
//unpack v to temphigh4 templow4
10468
//high4 = high4 * multiplier
10469
//low4 = low4 * multiplier
10470
//high4 = high4 + temphigh4
10471
//low4 = low4 + templow4
10472
//v = v + 0x10
10473
//if v < vend goto VSX_LOOP
10474
generateLabelInstruction(cg, TR::InstOpCode::label, node, VSXLabel);
10475
generateTrg1MemInstruction(cg, TR::InstOpCode::lvx, node, vtmp1Reg, TR::MemoryReference::createWithIndexReg(cg, valueReg, constant0Reg, 16));
10476
generateTrg1Src1Instruction(cg, TR::InstOpCode::vupkhsh, node, vtmp2Reg, vtmp1Reg);
10477
generateTrg1Src2Instruction(cg, TR::InstOpCode::vand, node, vtmp2Reg, vtmp2Reg, vunpackMaskReg);
10478
generateTrg1Src2Instruction(cg, TR::InstOpCode::vmuluwm, node, high4Reg, high4Reg, multiplierReg);
10479
generateTrg1Src2Instruction(cg, TR::InstOpCode::vadduwm, node, high4Reg, high4Reg, vtmp2Reg);
10480
generateTrg1Src1Instruction(cg, TR::InstOpCode::vupklsh, node, vtmp2Reg, vtmp1Reg);
10481
generateTrg1Src2Instruction(cg, TR::InstOpCode::vand, node, vtmp2Reg, vtmp2Reg, vunpackMaskReg);
10482
generateTrg1Src2Instruction(cg, TR::InstOpCode::vmuluwm, node, low4Reg, low4Reg, multiplierReg);
10483
generateTrg1Src2Instruction(cg, TR::InstOpCode::vadduwm, node, low4Reg, low4Reg, vtmp2Reg);
10484
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, valueReg, valueReg, 0x10);
10485
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp8, node, condReg, valueReg, vendReg);
10486
generateConditionalBranchInstruction(cg, TR::InstOpCode::blt, node, VSXLabel, condReg);
10487
10488
// POST_VSX:
10489
// shift and sum low4 and high4
10490
// move result to hashReg
10491
generateLabelInstruction(cg, TR::InstOpCode::label, node, POSTVSXLabel);
10492
10493
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, multiplierAddrReg, multiplierAddrReg, 0x10);
10494
generateTrg1MemInstruction(cg, TR::InstOpCode::lxvw4x, node, multiplierReg, TR::MemoryReference::createWithIndexReg(cg, multiplierAddrReg, constant0Reg, 16));
10495
generateTrg1Src2Instruction(cg, TR::InstOpCode::vmuluwm, node, high4Reg, high4Reg, multiplierReg);
10496
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, multiplierAddrReg, multiplierAddrReg, 0x10);
10497
generateTrg1MemInstruction(cg, TR::InstOpCode::lxvw4x, node, multiplierReg, TR::MemoryReference::createWithIndexReg(cg, multiplierAddrReg, constant0Reg, 16));
10498
generateTrg1Src2Instruction(cg, TR::InstOpCode::vmuluwm, node, low4Reg, low4Reg, multiplierReg);
10499
10500
generateTrg1Src2Instruction(cg, TR::InstOpCode::vadduwm, node, high4Reg, high4Reg, low4Reg);
10501
generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::vsldoi, node, vtmp1Reg, vconstant0Reg, high4Reg, 8);
10502
generateTrg1Src2Instruction(cg, TR::InstOpCode::vadduwm, node, high4Reg, high4Reg, vtmp1Reg);
10503
generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::vsldoi, node, vtmp1Reg, vconstant0Reg, high4Reg, 12);
10504
generateTrg1Src2Instruction(cg, TR::InstOpCode::vadduwm, node, high4Reg, high4Reg, vtmp1Reg);
10505
10506
generateTrg1Src2ImmInstruction(cg, TR::InstOpCode::vsldoi, node, vtmp1Reg, high4Reg, vconstant0Reg, 8);
10507
generateTrg1Src1Instruction(cg, TR::InstOpCode::mfvsrwz, node, hashReg, vtmp1Reg);
10508
10509
// Head of the serial loop
10510
generateLabelInstruction(cg, TR::InstOpCode::label, node, serialLabel);
10511
10512
// temp = hash
10513
// hash = hash << 5
10514
// hash = hash - temp
10515
// temp = v[i]
10516
// hash = hash + temp
10517
10518
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp8, node, condReg, valueReg, endReg);
10519
generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, endLabel, condReg);
10520
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, tempReg, hashReg);
10521
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, hashReg, hashReg, 5, 0xFFFFFFFFFFFFFFE0);
10522
generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, hashReg, tempReg, hashReg);
10523
generateTrg1MemInstruction(cg, TR::InstOpCode::lhzx, node, tempReg, TR::MemoryReference::createWithIndexReg(cg, valueReg, constant0Reg, 2));
10524
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, hashReg, hashReg, tempReg);
10525
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, valueReg, valueReg, 0x2);
10526
generateLabelInstruction(cg, TR::InstOpCode::b, node, serialLabel);
10527
10528
// End of this method
10529
TR::RegisterDependencyConditions *dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 16, cg->trMemory());
10530
dependencies->addPostCondition(valueReg, TR::RealRegister::NoReg);
10531
dependencies->getPostConditions()->getRegisterDependency(0)->setExcludeGPR0(); // valueReg
10532
10533
dependencies->addPostCondition(endReg, TR::RealRegister::NoReg);
10534
dependencies->addPostCondition(vendReg, TR::RealRegister::NoReg);
10535
dependencies->addPostCondition(hashReg, TR::RealRegister::NoReg);
10536
dependencies->addPostCondition(tempReg, TR::RealRegister::NoReg);
10537
dependencies->addPostCondition(constant0Reg, TR::RealRegister::NoReg);
10538
dependencies->addPostCondition(condReg, TR::RealRegister::NoReg);
10539
10540
dependencies->addPostCondition(multiplierAddrReg, TR::RealRegister::NoReg);
10541
dependencies->getPostConditions()->getRegisterDependency(7)->setExcludeGPR0(); // multiplierAddrReg
10542
10543
dependencies->addPostCondition(multiplierReg, TR::RealRegister::NoReg);
10544
dependencies->addPostCondition(high4Reg, TR::RealRegister::NoReg);
10545
dependencies->addPostCondition(low4Reg, TR::RealRegister::NoReg);
10546
dependencies->addPostCondition(vtmp1Reg, TR::RealRegister::NoReg);
10547
dependencies->addPostCondition(vtmp2Reg, TR::RealRegister::NoReg);
10548
dependencies->addPostCondition(vconstant0Reg, TR::RealRegister::NoReg);
10549
dependencies->addPostCondition(vconstantNegReg, TR::RealRegister::NoReg);
10550
dependencies->addPostCondition(vunpackMaskReg, TR::RealRegister::NoReg);
10551
10552
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, endLabel, dependencies);
10553
10554
node->setRegister(hashReg);
10555
cg->decReferenceCount(valueNode);
10556
cg->decReferenceCount(offsetNode);
10557
cg->decReferenceCount(countNode);
10558
10559
cg->stopUsingRegister(valueReg);
10560
cg->stopUsingRegister(endReg);
10561
cg->stopUsingRegister(vendReg);
10562
cg->stopUsingRegister(tempReg);
10563
cg->stopUsingRegister(constant0Reg);
10564
cg->stopUsingRegister(condReg);
10565
cg->stopUsingRegister(multiplierAddrReg);
10566
10567
cg->stopUsingRegister(multiplierReg);
10568
cg->stopUsingRegister(high4Reg);
10569
cg->stopUsingRegister(low4Reg);
10570
cg->stopUsingRegister(vtmp1Reg);
10571
cg->stopUsingRegister(vtmp2Reg);
10572
cg->stopUsingRegister(vconstant0Reg);
10573
cg->stopUsingRegister(vconstantNegReg);
10574
cg->stopUsingRegister(vunpackMaskReg);
10575
return hashReg;
10576
}
10577
10578
static TR::Register *inlineEncodeUTF16(TR::Node *node, TR::CodeGenerator *cg)
10579
{
10580
// tree looks like:
10581
// icall com.ibm.jit.JITHelpers.encodeUtf16{Big,Little}()
10582
// input ptr
10583
// output ptr
10584
// input length (in elements)
10585
// Number of elements converted returned
10586
10587
TR::MethodSymbol *symbol = node->getSymbol()->castToMethodSymbol();
10588
bool bigEndian = symbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_transformedEncodeUTF16Big;
10589
10590
// Set up register dependencies
10591
const int gprClobberCount = 5;
10592
const int fprClobberCount = 4;
10593
const int vrClobberCount = 6;
10594
const int crClobberCount = 2;
10595
const int totalDeps = crClobberCount + gprClobberCount + fprClobberCount + vrClobberCount + 3;
10596
TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(1, totalDeps, cg->trMemory());
10597
10598
TR::Register *inputReg = cg->gprClobberEvaluate(node->getChild(0));
10599
TR::Register *outputReg = cg->gprClobberEvaluate(node->getChild(1));
10600
TR::Register *inputLenReg = cg->gprClobberEvaluate(node->getChild(2));
10601
TR::Register *outputLenReg = cg->allocateRegister();
10602
10603
// Allocate clobbered registers
10604
TR::Register *gprClobbers[gprClobberCount], *fprClobbers[fprClobberCount], *vrClobbers[vrClobberCount], *crClobbers[crClobberCount];
10605
for (int i = 0; i < gprClobberCount; ++i) gprClobbers[i] = cg->allocateRegister(TR_GPR);
10606
for (int i = 0; i < fprClobberCount; ++i) fprClobbers[i] = cg->allocateRegister(TR_FPR);
10607
for (int i = 0; i < vrClobberCount; ++i) vrClobbers[i] = cg->allocateRegister(TR_VRF);
10608
for (int i = 0; i < crClobberCount; ++i) crClobbers[i] = cg->allocateRegister(TR_CCR);
10609
10610
// Add the pre and post conditions
10611
// Input and output registers
10612
deps->addPreCondition(inputReg, TR::RealRegister::gr3);
10613
10614
deps->addPostCondition(outputLenReg, TR::RealRegister::gr3);
10615
deps->addPostCondition(outputReg, TR::RealRegister::gr4);
10616
deps->addPostCondition(inputLenReg, TR::RealRegister::gr5);
10617
10618
//CCR.
10619
deps->addPostCondition(crClobbers[0], TR::RealRegister::cr0);
10620
deps->addPostCondition(crClobbers[1], TR::RealRegister::cr6);
10621
10622
//GPRs + Trampoline
10623
deps->addPostCondition(gprClobbers[0], TR::RealRegister::gr6);
10624
deps->addPostCondition(gprClobbers[1], TR::RealRegister::gr7);
10625
deps->addPostCondition(gprClobbers[2], TR::RealRegister::gr8);
10626
deps->addPostCondition(gprClobbers[3], TR::RealRegister::gr9);
10627
deps->addPostCondition(gprClobbers[4], TR::RealRegister::gr11);
10628
10629
//VR's
10630
deps->addPostCondition(vrClobbers[0], TR::RealRegister::vr0);
10631
deps->addPostCondition(vrClobbers[1], TR::RealRegister::vr1);
10632
deps->addPostCondition(vrClobbers[2], TR::RealRegister::vr2);
10633
deps->addPostCondition(vrClobbers[3], TR::RealRegister::vr3);
10634
deps->addPostCondition(vrClobbers[4], TR::RealRegister::vr4);
10635
deps->addPostCondition(vrClobbers[5], TR::RealRegister::vr5);
10636
10637
//FP/VSR
10638
deps->addPostCondition(fprClobbers[0], TR::RealRegister::fp0);
10639
deps->addPostCondition(fprClobbers[1], TR::RealRegister::fp1);
10640
deps->addPostCondition(fprClobbers[2], TR::RealRegister::fp2);
10641
deps->addPostCondition(fprClobbers[3], TR::RealRegister::fp3);
10642
10643
// Generate helper call
10644
TR_RuntimeHelper helper;
10645
helper = bigEndian ? TR_PPCencodeUTF16Big : TR_PPCencodeUTF16Little;
10646
TR::SymbolReference *helperSym = cg->comp()->getSymRefTab()->findOrCreateRuntimeHelper(helper);
10647
generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)helperSym->getMethodAddress(), deps, helperSym);
10648
10649
for (uint32_t i = 0; i < node->getNumChildren(); ++i) cg->decReferenceCount(node->getChild(i));
10650
10651
// Spill the clobbered registers
10652
if (inputReg != node->getChild(0)->getRegister()) cg->stopUsingRegister(inputReg);
10653
if (outputReg != node->getChild(1)->getRegister()) cg->stopUsingRegister(outputReg);
10654
if (inputLenReg != node->getChild(2)->getRegister()) cg->stopUsingRegister(inputLenReg);
10655
for (int i = 0; i < gprClobberCount; ++i) cg->stopUsingRegister(gprClobbers[i]);
10656
for (int i = 0; i < vrClobberCount; ++i) cg->stopUsingRegister(vrClobbers[i]);
10657
for (int i = 0; i < fprClobberCount; ++i) cg->stopUsingRegister(fprClobbers[i]);
10658
for (int i = 0; i < crClobberCount; ++i) cg->stopUsingRegister(crClobbers[i]);
10659
10660
cg->machine()->setLinkRegisterKilled(true);
10661
cg->setHasCall();
10662
node->setRegister(outputLenReg);
10663
10664
return outputLenReg;
10665
}
10666
10667
static TR::Register *inlineIntrinsicIndexOf_P10(TR::Node *node, TR::CodeGenerator *cg, bool isLatin1)
10668
{
10669
static bool disableIndexOfStringIntrinsic = feGetEnv("TR_DisableIndexOfStringIntrinsic") != NULL;
10670
if (disableIndexOfStringIntrinsic)
10671
return nullptr;
10672
TR::Compilation *comp = cg->comp();
10673
auto vectorCompareOp = isLatin1 ? TR::InstOpCode::vcmpequb_r : TR::InstOpCode::vcmpequh_r;
10674
TR::InstOpCode::Mnemonic scalarLoadOp = isLatin1 ? TR::InstOpCode::lbzx : TR::InstOpCode::lhzx;
10675
10676
10677
TR::Register *array = cg->evaluate(node->getChild(1));
10678
TR::Register *ch = cg->evaluate(node->getChild(2));
10679
TR::Register *offset = cg->evaluate(node->getChild(3));
10680
TR::Register *length = cg->evaluate(node->getChild(4));
10681
10682
TR::LabelSymbol *startLabel = generateLabelSymbol(cg);
10683
TR::LabelSymbol *mainLoop = generateLabelSymbol(cg);
10684
TR::LabelSymbol *residueLabel = generateLabelSymbol(cg);
10685
TR::LabelSymbol *resultLabel = generateLabelSymbol(cg);
10686
TR::LabelSymbol *endLabel = generateLabelSymbol(cg);
10687
10688
TR::Register *cr6 = cg->allocateRegister(TR_CCR);
10689
10690
TR::Register *position = cg->allocateRegister();
10691
TR::Register *endPos = cg->allocateRegister();
10692
TR::Register *arrAddress = cg->allocateRegister();
10693
TR::Register *result = cg->allocateRegister();
10694
TR::Register *temp = cg->allocateRegister();
10695
TR::Register *vec0 = cg->allocateRegister(TR_VRF);
10696
TR::Register *vec1 = cg->allocateRegister(TR_VRF);
10697
TR::Register *vec2 = cg->allocateRegister(TR_VRF);
10698
10699
startLabel->setStartInternalControlFlow();
10700
endLabel->setEndInternalControlFlow();
10701
10702
generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);
10703
10704
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, result, -1);
10705
// check empty
10706
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, cr6, offset, length);
10707
generateConditionalBranchInstruction(cg, TR::InstOpCode::bge, node, endLabel, cr6);
10708
10709
generateTrg1Src1Instruction(cg, TR::InstOpCode::extsw, node, position, offset);
10710
generateTrg1Src1Instruction(cg, TR::InstOpCode::extsw, node, endPos, length);
10711
10712
// sanity check : if str isLatin1, then ch should be isLatin1 too.
10713
if (isLatin1)
10714
{
10715
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, temp, ch, 24, 0xFF);
10716
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, cr6, temp, 0);
10717
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, endLabel, cr6);
10718
}
10719
10720
10721
if (!isLatin1)
10722
{
10723
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, position, position, position);
10724
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, endPos, endPos, endPos);
10725
}
10726
10727
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, arrAddress, array, TR::Compiler->om.contiguousArrayHeaderSizeInBytes());
10728
10729
// match first byte
10730
generateTrg1MemInstruction(cg, scalarLoadOp, node, temp, TR::MemoryReference::createWithIndexReg(cg, position, arrAddress, isLatin1 ? 1 : 2));
10731
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, cr6, temp, ch);
10732
generateTrg1Src3Instruction(cg, TR::InstOpCode::iseleq, node, result, offset, result, cr6);
10733
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, endLabel, cr6);
10734
10735
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, position, position, isLatin1 ? 1 : 2);
10736
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, cr6, position, endPos);
10737
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, endLabel, cr6);
10738
10739
generateTrg1Src1Instruction(cg, TR::InstOpCode::mtvsrwz, node, vec1, ch);
10740
if (isLatin1)
10741
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::vspltb, node, vec1, vec1, 7);
10742
else
10743
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::vsplth, node, vec1, vec1, 3);
10744
10745
10746
generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, temp, position, endPos);
10747
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, endPos, temp, 0, 0xF);
10748
generateShiftRightLogicalImmediate(cg, node, temp, temp, 4);
10749
10750
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, cr6, temp, 0);
10751
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, residueLabel, cr6);
10752
10753
generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, temp);
10754
10755
generateLabelInstruction(cg, TR::InstOpCode::label, node, mainLoop); // mainloop
10756
if (!isLatin1)
10757
{
10758
generateTrg1Src2Instruction(cg, TR::InstOpCode::lxvh8x, node, vec0, arrAddress, position);
10759
generateTrg1Src2Instruction(cg, TR::InstOpCode::vcmpequh_r, node, vec0, vec0, vec1);
10760
}
10761
else
10762
{
10763
generateTrg1Src2Instruction(cg, TR::InstOpCode::lxvb16x, node, vec0, arrAddress, position);
10764
generateTrg1Src2Instruction(cg, TR::InstOpCode::vcmpequb_r, node, vec0, vec0, vec1);
10765
}
10766
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, resultLabel, cr6);
10767
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, position, position, 16);
10768
generateConditionalBranchInstruction(cg, TR::InstOpCode::bdnz, node, mainLoop, cr6);
10769
10770
generateLabelInstruction(cg, TR::InstOpCode::label, node, residueLabel);
10771
10772
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::cmpi4, node, cr6, endPos, 0);
10773
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, endLabel, cr6);
10774
10775
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, arrAddress, arrAddress, position);
10776
generateShiftLeftImmediateLong(cg, node, endPos, endPos, 56);
10777
10778
generateTrg1Src2Instruction(cg, TR::InstOpCode::lxvll, node, vec0, arrAddress, endPos);
10779
10780
10781
if (comp->target().cpu.isLittleEndian() && !isLatin1)
10782
{
10783
generateTrg1ImmInstruction(cg, TR::InstOpCode::vspltisb, node, vec2, 8);
10784
generateTrg1Src2Instruction(cg, TR::InstOpCode::vrlq, node, vec1, vec1, vec2);
10785
}
10786
10787
if (isLatin1)
10788
generateTrg1Src2Instruction(cg, TR::InstOpCode::vcmpequb, node, vec0, vec0, vec1);
10789
else
10790
generateTrg1Src2Instruction(cg, TR::InstOpCode::vcmpequh, node, vec0, vec0, vec1);
10791
10792
generateLabelInstruction(cg, TR::InstOpCode::label, node, resultLabel); // resultLabel
10793
generateTrg1Src1Instruction(cg, TR::InstOpCode::vclzlsbb, node, temp, vec0);
10794
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, temp, temp, position);
10795
10796
if (!isLatin1)
10797
{
10798
generateShiftRightLogicalImmediate(cg, node, temp, temp, 1);
10799
}
10800
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, cr6, temp, length);
10801
10802
generateTrg1Src3Instruction(cg, TR::InstOpCode::isellt, node, result, temp, result, cr6);
10803
// end
10804
10805
TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 13, cg->trMemory());
10806
10807
deps->addPostCondition(array, TR::RealRegister::NoReg);
10808
deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();
10809
deps->addPostCondition(ch, TR::RealRegister::NoReg);
10810
deps->addPostCondition(offset, TR::RealRegister::NoReg);
10811
deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();
10812
deps->addPostCondition(length, TR::RealRegister::NoReg);
10813
10814
deps->addPostCondition(cr6, TR::RealRegister::cr6);
10815
10816
deps->addPostCondition(position, TR::RealRegister::NoReg);
10817
deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();
10818
deps->addPostCondition(endPos, TR::RealRegister::NoReg);
10819
deps->addPostCondition(arrAddress, TR::RealRegister::NoReg);
10820
deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();
10821
deps->addPostCondition(result, TR::RealRegister::NoReg);
10822
deps->addPostCondition(temp, TR::RealRegister::NoReg);
10823
deps->addPostCondition(vec0, TR::RealRegister::NoReg);
10824
deps->addPostCondition(vec1, TR::RealRegister::NoReg);
10825
deps->addPostCondition(vec2, TR::RealRegister::NoReg);
10826
10827
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, endLabel, deps);
10828
10829
deps->stopUsingDepRegs(cg, result);
10830
10831
node->setRegister(result);
10832
10833
cg->decReferenceCount(node->getChild(0));
10834
cg->decReferenceCount(node->getChild(1));
10835
cg->decReferenceCount(node->getChild(2));
10836
cg->decReferenceCount(node->getChild(3));
10837
cg->decReferenceCount(node->getChild(4));
10838
10839
return result;
10840
}
10841
10842
static TR::Register *inlineIntrinsicIndexOf(TR::Node *node, TR::CodeGenerator *cg, bool isLatin1)
10843
{
10844
static bool disableIndexOfStringIntrinsic = feGetEnv("TR_DisableIndexOfStringIntrinsic") != NULL;
10845
if (disableIndexOfStringIntrinsic)
10846
return nullptr;
10847
TR::Compilation *comp = cg->comp();
10848
auto vectorCompareOp = isLatin1 ? TR::InstOpCode::vcmpequb_r : TR::InstOpCode::vcmpequh_r;
10849
auto scalarLoadOp = isLatin1 ? TR::InstOpCode::lbzx : TR::InstOpCode::lhzx;
10850
10851
TR::Register *array = cg->evaluate(node->getChild(1));
10852
TR::Register *ch = cg->evaluate(node->getChild(2));
10853
TR::Register *offset = cg->evaluate(node->getChild(3));
10854
TR::Register *length = cg->evaluate(node->getChild(4));
10855
10856
TR::Register *cr0 = cg->allocateRegister(TR_CCR);
10857
TR::Register *cr6 = cg->allocateRegister(TR_CCR);
10858
10859
TR::Register *zeroRegister = cg->allocateRegister();
10860
TR::Register *result = cg->allocateRegister();
10861
TR::Register *arrAddress = cg->allocateRegister();
10862
TR::Register *currentAddress = cg->allocateRegister();
10863
TR::Register *endAddress = cg->allocateRegister();
10864
10865
TR::Register *targetVector = cg->allocateRegister(TR_VRF);
10866
TR::Register *targetVectorNot = cg->allocateRegister(TR_VRF);
10867
TR::Register *searchVector = cg->allocateRegister(TR_VRF);
10868
TR::Register *permuteVector = cg->allocateRegister(TR_VRF);
10869
10870
TR_PPCScratchRegisterManager *srm = cg->generateScratchRegisterManager();
10871
10872
TR::LabelSymbol *startLabel = generateLabelSymbol(cg);
10873
TR::LabelSymbol *notSmallLabel = generateLabelSymbol(cg);
10874
TR::LabelSymbol *vectorLoopLabel = generateLabelSymbol(cg);
10875
TR::LabelSymbol *residueLabel = generateLabelSymbol(cg);
10876
TR::LabelSymbol *notFoundLabel = generateLabelSymbol(cg);
10877
TR::LabelSymbol *foundLabel = generateLabelSymbol(cg);
10878
TR::LabelSymbol *foundExactLabel = generateLabelSymbol(cg);
10879
TR::LabelSymbol *endLabel = generateLabelSymbol(cg);
10880
10881
startLabel->setStartInternalControlFlow();
10882
endLabel->setEndInternalControlFlow();
10883
10884
generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);
10885
10886
// Special case for empty strings, which always return -1
10887
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, cr0, offset, length);
10888
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, notFoundLabel, cr0);
10889
10890
// IMPORTANT: The upper 32 bits of a 64-bit register containing an int are undefined. Since the
10891
// indices are being passed in as ints, we must ensure that their upper 32 bits are not garbage.
10892
generateTrg1Src1Instruction(cg, TR::InstOpCode::extsw, node, result, offset);
10893
generateTrg1Src1Instruction(cg, TR::InstOpCode::extsw, node, endAddress, length);
10894
10895
if (!isLatin1)
10896
{
10897
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, result, result, result);
10898
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, endAddress, endAddress, endAddress);
10899
}
10900
10901
if (node->getChild(3)->getReferenceCount() == 1)
10902
srm->donateScratchRegister(offset);
10903
if (node->getChild(4)->getReferenceCount() == 1)
10904
srm->donateScratchRegister(length);
10905
10906
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, arrAddress, array, TR::Compiler->om.contiguousArrayHeaderSizeInBytes());
10907
if (node->getChild(1)->getReferenceCount() == 1)
10908
srm->donateScratchRegister(array);
10909
10910
// Handle the first character using a simple scalar compare. Otherwise, first character matches
10911
// would be slower than the old scalar comparison loop. This is a problem since first character
10912
// matches are common in certain contexts, e.g. StringTokenizer where the default first character
10913
// to each String.indexOf call is ' ', which is the most common whitespace character.
10914
{
10915
TR::Register *value = srm->findOrCreateScratchRegister();
10916
TR::Register *zxTargetScalar = srm->findOrCreateScratchRegister();
10917
10918
// Since we're going to do a load followed immediately by a comparison, we need to ensure that
10919
// the target scalar is zero-extended and *not* sign-extended.
10920
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rlwinm, node, zxTargetScalar, ch, 0, isLatin1 ? 0xff : 0xffff);
10921
10922
generateTrg1MemInstruction(cg, scalarLoadOp, node, value, TR::MemoryReference::createWithIndexReg(cg, result, arrAddress, isLatin1 ? 1 : 2));
10923
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp4, node, cr0, value, zxTargetScalar);
10924
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, foundExactLabel, cr0);
10925
10926
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, result, result, isLatin1 ? 1 : 2);
10927
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp8, node, cr0, result, endAddress);
10928
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, notFoundLabel, cr0);
10929
10930
srm->reclaimScratchRegister(zxTargetScalar);
10931
srm->reclaimScratchRegister(value);
10932
}
10933
10934
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, zeroRegister, 0);
10935
10936
// Calculate the actual addresses of the start and end points
10937
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, endAddress, arrAddress, endAddress);
10938
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, currentAddress, arrAddress, result);
10939
10940
// Splat the value to be compared against and its bitwise complement into two vector registers
10941
// for later use
10942
generateTrg1Src1Instruction(cg, TR::InstOpCode::mtvsrwz, node, targetVector, ch);
10943
if (node->getChild(2)->getReferenceCount() == 1)
10944
srm->donateScratchRegister(ch);
10945
if (isLatin1)
10946
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::vspltb, node, targetVector, targetVector, 7);
10947
else
10948
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::vsplth, node, targetVector, targetVector, 3);
10949
generateTrg1Src2Instruction(cg, TR::InstOpCode::vnor, node, targetVectorNot, targetVector, targetVector);
10950
10951
TR::Register *endVectorAddress = srm->findOrCreateScratchRegister();
10952
TR::Register *startVectorAddress = srm->findOrCreateScratchRegister();
10953
10954
// Calculate the end address for what can be compared using full vector compares. After reaching
10955
// this address, the remaining comparisons (if required) will need special handling.
10956
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicr, node, endVectorAddress, endAddress, 0, CONSTANT64(0xfffffffffffffff0));
10957
10958
// Check if the entire string is contained within a single 16-byte aligned section. If this
10959
// happens, we need to handle that case specially.
10960
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicr, node, startVectorAddress, currentAddress, 0, CONSTANT64(0xfffffffffffffff0));
10961
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp8, node, cr0, startVectorAddress, endVectorAddress);
10962
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, notSmallLabel, cr0);
10963
10964
// If we got here, then the entire string to search is contained within a single 16-byte aligned
10965
// vector and the end of the string is not aligned to the end of the vector. We don't know
10966
// whether the start of the string is aligned, but we'll assume it isn't since that just results
10967
// in a few unnecessary operations producing the correct answer regardless.
10968
10969
// First, we read in an entire 16-byte aligned vector containing the entire string. Since this
10970
// load is done with 16-byte natural alignment, this load can't cross a page boundary and cause
10971
// an unexpected page fault. However, this will read some garbage at the start and end of the
10972
// vector. Assume that we read n bytes of garbage before the string and m bytes of garbage after
10973
// the string.
10974
generateTrg1MemInstruction(cg, TR::InstOpCode::lvx, node, searchVector, TR::MemoryReference::createWithIndexReg(cg, zeroRegister, currentAddress, 16));
10975
10976
{
10977
TR::Register *scratchRegister = srm->findOrCreateScratchRegister();
10978
10979
// We need to ensure that the garbage we read can't compare as equal to the target value for
10980
// obvious reasons. In order to accomplish this, we first rotate forwards by m bytes. This
10981
// places all garbage at the beginning of the vector.
10982
generateTrg1Src1Instruction(cg, TR::InstOpCode::neg, node, scratchRegister, endAddress);
10983
generateTrg1Src2Instruction(cg, comp->target().cpu.isLittleEndian() ? TR::InstOpCode::lvsl : TR::InstOpCode::lvsr, node, permuteVector, zeroRegister, scratchRegister);
10984
generateTrg1Src3Instruction(cg, TR::InstOpCode::vperm, node, searchVector, searchVector, searchVector, permuteVector);
10985
10986
// Next, we shift the vector backwards by (n + m) bytes shifting in the bitwise complement of
10987
// the target value. This causes the garbage to end up at the vector register, having been
10988
// replaced with a bit pattern that can never compare as equal to the target value.
10989
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, scratchRegister, scratchRegister, currentAddress);
10990
if (comp->target().cpu.isLittleEndian())
10991
{
10992
generateTrg1Src2Instruction(cg, TR::InstOpCode::lvsr, node, permuteVector, zeroRegister, scratchRegister);
10993
generateTrg1Src3Instruction(cg, TR::InstOpCode::vperm, node, searchVector, targetVectorNot, searchVector, permuteVector);
10994
}
10995
else
10996
{
10997
generateTrg1Src2Instruction(cg, TR::InstOpCode::lvsl, node, permuteVector, zeroRegister, scratchRegister);
10998
generateTrg1Src3Instruction(cg, TR::InstOpCode::vperm, node, searchVector, searchVector, targetVectorNot, permuteVector);
10999
}
11000
11001
srm->reclaimScratchRegister(scratchRegister);
11002
11003
// Now the search vector is ready for comparison: none of the garbage can compare as equal to
11004
// our target value and the start of the vector is now aligned to the start of the string. So
11005
// we can now perform the comparison as normal.
11006
generateTrg1Src2Instruction(cg, vectorCompareOp, node, searchVector, searchVector, targetVector);
11007
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, foundLabel, cr6);
11008
generateLabelInstruction(cg, TR::InstOpCode::b, node, notFoundLabel);
11009
}
11010
11011
generateLabelInstruction(cg, TR::InstOpCode::label, node, notSmallLabel);
11012
11013
// Check if we already have 16-byte alignment. Vector loads require 16-byte alignment, so if we
11014
// aren't properly aligned, we'll need to handle comparisons specially until we achieve 16-byte
11015
// alignment.
11016
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp8, node, cr0, currentAddress, startVectorAddress);
11017
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, vectorLoopLabel, cr0);
11018
11019
// We are not on a 16-byte boundary, so we cannot directly load the first 16 bytes of the string
11020
// for comparison. Instead, we load the 16 byte vector starting from the 16-byte aligned section
11021
// containing the start of the string. Since we have 16-byte natural alignment, this can't cause
11022
// an unexpected page fault.
11023
generateTrg1MemInstruction(cg, TR::InstOpCode::lvx, node, searchVector, TR::MemoryReference::createWithIndexReg(cg, zeroRegister, currentAddress, 16));
11024
11025
// However, before we can run any comparisons on the loaded vector, we must ensure that the extra
11026
// garbage read before the start of the string can't match the target character. To do this, we
11027
// shift the loaded vector backwards by n bytes shifting in the bitwise complement of the target
11028
// character.
11029
if (comp->target().cpu.isLittleEndian())
11030
{
11031
generateTrg1Src2Instruction(cg, TR::InstOpCode::lvsr, node, permuteVector, zeroRegister, currentAddress);
11032
generateTrg1Src3Instruction(cg, TR::InstOpCode::vperm, node, searchVector, targetVectorNot, searchVector, permuteVector);
11033
}
11034
else
11035
{
11036
generateTrg1Src2Instruction(cg, TR::InstOpCode::lvsl, node, permuteVector, zeroRegister, currentAddress);
11037
generateTrg1Src3Instruction(cg, TR::InstOpCode::vperm, node, searchVector, searchVector, targetVectorNot, permuteVector);
11038
}
11039
11040
// Now our vector is ready for comparison: no garbage can match the target value and the start of
11041
// the vector is now aligned to the start of the string.
11042
generateTrg1Src2Instruction(cg, vectorCompareOp, node, searchVector, searchVector, targetVector);
11043
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, foundLabel, cr6);
11044
11045
// If the first vector didn't match, then we can slide right into the standard vectorized loop.
11046
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, currentAddress, startVectorAddress, 0x10);
11047
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp8, node, cr0, currentAddress, endVectorAddress);
11048
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, residueLabel, cr0);
11049
11050
srm->reclaimScratchRegister(startVectorAddress);
11051
11052
// This is the heart of the vectorized loop, working just like any standard vectorized loop.
11053
generateLabelInstruction(cg, TR::InstOpCode::label, node, vectorLoopLabel);
11054
generateTrg1MemInstruction(cg, TR::InstOpCode::lvx, node, searchVector, TR::MemoryReference::createWithIndexReg(cg, zeroRegister, currentAddress, 16));
11055
generateTrg1Src2Instruction(cg, vectorCompareOp, node, searchVector, searchVector, targetVector);
11056
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, foundLabel, cr6);
11057
11058
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, currentAddress, currentAddress, 0x10);
11059
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp8, node, cr0, currentAddress, endVectorAddress);
11060
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, vectorLoopLabel, cr0);
11061
11062
srm->reclaimScratchRegister(endVectorAddress);
11063
11064
// Now we're done with the part of the loop which can be handled as a normal vectorized loop. If
11065
// there are no more elements to compare, we're done. Otherwise, we need to handle the residue.
11066
generateLabelInstruction(cg, TR::InstOpCode::label, node, residueLabel);
11067
generateTrg1Src2Instruction(cg, TR::InstOpCode::cmp8, node, cr0, currentAddress, endAddress);
11068
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, notFoundLabel, cr0);
11069
11070
// Usually, we would need a residue loop here, but it's safe to read beyond the end of the string
11071
// here. Since our load will have 16-byte natural alignment, it can't cross a page boundary and
11072
// cause an unexpected page fault.
11073
generateTrg1MemInstruction(cg, TR::InstOpCode::lvx, node, searchVector, TR::MemoryReference::createWithIndexReg(cg, zeroRegister, currentAddress, 16));
11074
11075
TR::Register *shiftAmount = srm->findOrCreateScratchRegister();
11076
11077
// Before we can run our comparison, we need to ensure that the garbage from beyond the end of
11078
// the string cannot compare as equal to our target value. To do this, we first rotate the vector
11079
// forwards by n bytes then shift back by n bytes, shifting in the bitwise complement of the
11080
// target value.
11081
generateTrg1Src1Instruction(cg, TR::InstOpCode::neg, node, shiftAmount, endAddress);
11082
if (comp->target().cpu.isLittleEndian())
11083
{
11084
generateTrg1Src2Instruction(cg, TR::InstOpCode::lvsl, node, permuteVector, zeroRegister, shiftAmount);
11085
generateTrg1Src3Instruction(cg, TR::InstOpCode::vperm, node, searchVector, searchVector, searchVector, permuteVector);
11086
generateTrg1Src2Instruction(cg, TR::InstOpCode::lvsr, node, permuteVector, zeroRegister, shiftAmount);
11087
generateTrg1Src3Instruction(cg, TR::InstOpCode::vperm, node, searchVector, targetVectorNot, searchVector, permuteVector);
11088
}
11089
else
11090
{
11091
generateTrg1Src2Instruction(cg, TR::InstOpCode::lvsr, node, permuteVector, zeroRegister, shiftAmount);
11092
generateTrg1Src3Instruction(cg, TR::InstOpCode::vperm, node, searchVector, searchVector, searchVector, permuteVector);
11093
generateTrg1Src2Instruction(cg, TR::InstOpCode::lvsl, node, permuteVector, zeroRegister, shiftAmount);
11094
generateTrg1Src3Instruction(cg, TR::InstOpCode::vperm, node, searchVector, searchVector, targetVectorNot, permuteVector);
11095
}
11096
11097
srm->reclaimScratchRegister(shiftAmount);
11098
11099
// Now we run our comparison as normal
11100
generateTrg1Src2Instruction(cg, vectorCompareOp, node, searchVector, searchVector, targetVector);
11101
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, foundLabel, cr6);
11102
11103
generateLabelInstruction(cg, TR::InstOpCode::label, node, notFoundLabel);
11104
11105
// We've looked through the entire string and didn't find our target character, so return the
11106
// sentinel value -1
11107
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, result, -1);
11108
generateLabelInstruction(cg, TR::InstOpCode::b, node, endLabel);
11109
11110
generateLabelInstruction(cg, TR::InstOpCode::label, node, foundLabel);
11111
11112
// We've managed to find a match for the target value in the loaded vector, but we don't yet know
11113
// which element of the loaded vector is the first match. The comparison will have set matching
11114
// elements in the vector to -1 and non-matching elements to 0. We can find the first matching
11115
// element by gathering the first bit of every byte in the vector register...
11116
11117
// Set permuteVector = 0x000102030405060708090a0b0c0d0e0f
11118
generateTrg1Src2Instruction(cg, TR::InstOpCode::lvsl, node, permuteVector, zeroRegister, zeroRegister);
11119
11120
// For little-endian, reverse permuteVector so that we can find the first set bit using a count
11121
// leading zeroes test instead of a count trailing zeroes test. This is necessary since cnttzw
11122
// wasn't introduced until Power 9.
11123
if (comp->target().cpu.isLittleEndian())
11124
{
11125
generateTrg1ImmInstruction(cg, TR::InstOpCode::vspltisb, node, targetVector, 0x0f);
11126
generateTrg1Src2Instruction(cg, TR::InstOpCode::vsububm, node, permuteVector, targetVector, permuteVector);
11127
}
11128
11129
// Set permuteVector = 0x00081018202830384048505860687078 (reversed for LE)
11130
generateTrg1ImmInstruction(cg, TR::InstOpCode::vspltisb, node, targetVector, 3);
11131
generateTrg1Src2Instruction(cg, TR::InstOpCode::vslb, node, permuteVector, permuteVector, targetVector);
11132
11133
generateTrg1Src2Instruction(cg, TR::InstOpCode::vbpermq, node, searchVector, searchVector, permuteVector);
11134
generateTrg1Src1Instruction(cg, TR::InstOpCode::mfvsrwz, node, result, searchVector);
11135
11136
// Then count the number of leading zeroes from the obtained result. This tells us the index (in
11137
// bytes) of the first matching element in the vector. Note that there is no way to count leading
11138
// zeroes of a half-word, so we count leading zeroes of a word and subtract 16 since the value
11139
// we're interested in is in the least significant half-word.
11140
generateTrg1Src1Instruction(cg, TR::InstOpCode::cntlzw, node, result, result);
11141
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, result, result, -16);
11142
11143
// Finally, combine this with the address of the last vector load to find the address of the
11144
// first matching element in the string. Finally, use this to calculate the corresponding index.
11145
generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, result, result, currentAddress);
11146
generateTrg1Src2Instruction(cg, TR::InstOpCode::subf, node, result, arrAddress, result);
11147
11148
generateLabelInstruction(cg, TR::InstOpCode::label, node, foundExactLabel);
11149
if (!isLatin1)
11150
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::srawi, node, result, result, 1);
11151
11152
TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 15 + srm->numAvailableRegisters(), cg->trMemory());
11153
11154
if (node->getChild(1)->getReferenceCount() != 1)
11155
{
11156
deps->addPostCondition(array, TR::RealRegister::NoReg);
11157
deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();
11158
}
11159
if (node->getChild(2)->getReferenceCount() != 1)
11160
deps->addPostCondition(ch, TR::RealRegister::NoReg);
11161
if (node->getChild(3)->getReferenceCount() != 1)
11162
deps->addPostCondition(offset, TR::RealRegister::NoReg);
11163
if (node->getChild(4)->getReferenceCount() != 1)
11164
deps->addPostCondition(length, TR::RealRegister::NoReg);
11165
11166
deps->addPostCondition(cr0, TR::RealRegister::cr0);
11167
deps->addPostCondition(cr6, TR::RealRegister::cr6);
11168
11169
deps->addPostCondition(zeroRegister, TR::RealRegister::NoReg);
11170
deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();
11171
deps->addPostCondition(result, TR::RealRegister::NoReg);
11172
deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();
11173
deps->addPostCondition(arrAddress, TR::RealRegister::NoReg);
11174
deps->addPostCondition(currentAddress, TR::RealRegister::NoReg);
11175
deps->getPostConditions()->getRegisterDependency(deps->getAddCursorForPost() - 1)->setExcludeGPR0();
11176
deps->addPostCondition(endAddress, TR::RealRegister::NoReg);
11177
11178
deps->addPostCondition(targetVector, TR::RealRegister::NoReg);
11179
deps->addPostCondition(targetVectorNot, TR::RealRegister::NoReg);
11180
deps->addPostCondition(searchVector, TR::RealRegister::NoReg);
11181
deps->addPostCondition(permuteVector, TR::RealRegister::NoReg);
11182
11183
srm->addScratchRegistersToDependencyList(deps, true);
11184
11185
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, endLabel, deps);
11186
11187
deps->stopUsingDepRegs(cg, result);
11188
11189
node->setRegister(result);
11190
11191
cg->decReferenceCount(node->getChild(0));
11192
cg->decReferenceCount(node->getChild(1));
11193
cg->decReferenceCount(node->getChild(2));
11194
cg->decReferenceCount(node->getChild(3));
11195
cg->decReferenceCount(node->getChild(4));
11196
11197
return result;
11198
}
11199
11200
/*
11201
* Arraycopy evaluator needs a version of inlineArrayCopy that can be used inside internal control flow. For this version of inlineArrayCopy, registers must
11202
* be allocated outside of this function so the dependency at the end of the control flow knows about them.
11203
*/
11204
static void inlineArrayCopy_ICF(TR::Node *node, int64_t byteLen, TR::Register *src, TR::Register *dst, TR::CodeGenerator *cg, TR::Register *cndReg,
11205
TR::Register *tmp1Reg, TR::Register *tmp2Reg, TR::Register *tmp3Reg, TR::Register *tmp4Reg,
11206
TR::Register *fp1Reg, TR::Register *fp2Reg, TR::Register *fp3Reg, TR::Register *fp4Reg)
11207
{
11208
if (byteLen == 0)
11209
return;
11210
11211
bool postP10CopyInline = cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10) &&
11212
cg->comp()->target().cpu.supportsFeature(OMR_FEATURE_PPC_HAS_VSX);
11213
11214
if (postP10CopyInline)
11215
{
11216
// tmp1Reg and fp1Reg can be used: fp1Reg is a VSX_VECTOR
11217
11218
int32_t iteration64 = byteLen >> 6, residue64 = byteLen & 0x3F, standingOffset = 0;
11219
11220
if (iteration64 > 0)
11221
{
11222
TR::LabelSymbol *loopStart;
11223
11224
if (iteration64 > 1)
11225
{
11226
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tmp1Reg, iteration64);
11227
generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, tmp1Reg);
11228
11229
loopStart = generateLabelSymbol(cg);
11230
generateLabelInstruction(cg, TR::InstOpCode::label, node, loopStart);
11231
}
11232
11233
generateTrg1MemInstruction(cg, TR::InstOpCode::lxv, node, fp1Reg, TR::MemoryReference::createWithDisplacement(cg, src, 0, 16));
11234
generateMemSrc1Instruction(cg, TR::InstOpCode::stxv, node, TR::MemoryReference::createWithDisplacement(cg, dst, 0, 16), fp1Reg);
11235
generateTrg1MemInstruction(cg, TR::InstOpCode::lxv, node, fp1Reg, TR::MemoryReference::createWithDisplacement(cg, src, 16, 16));
11236
generateMemSrc1Instruction(cg, TR::InstOpCode::stxv, node, TR::MemoryReference::createWithDisplacement(cg, dst, 16, 16), fp1Reg);
11237
generateTrg1MemInstruction(cg, TR::InstOpCode::lxv, node, fp1Reg, TR::MemoryReference::createWithDisplacement(cg, src, 32, 16));
11238
generateMemSrc1Instruction(cg, TR::InstOpCode::stxv, node, TR::MemoryReference::createWithDisplacement(cg, dst, 32, 16), fp1Reg);
11239
generateTrg1MemInstruction(cg, TR::InstOpCode::lxv, node, fp1Reg, TR::MemoryReference::createWithDisplacement(cg, src, 48, 16));
11240
generateMemSrc1Instruction(cg, TR::InstOpCode::stxv, node, TR::MemoryReference::createWithDisplacement(cg, dst, 48, 16), fp1Reg);
11241
11242
if (iteration64 > 1)
11243
{
11244
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, src, src, 64);
11245
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, dst, dst, 64);
11246
generateConditionalBranchInstruction(cg, TR::InstOpCode::bdnz, node, loopStart, cndReg);
11247
}
11248
else
11249
standingOffset = 64;
11250
}
11251
11252
for (int32_t i = 0; i < (residue64>>4); i++)
11253
{
11254
generateTrg1MemInstruction(cg, TR::InstOpCode::lxv, node, fp1Reg, TR::MemoryReference::createWithDisplacement(cg, src, standingOffset+i*16, 16));
11255
generateMemSrc1Instruction(cg, TR::InstOpCode::stxv, node, TR::MemoryReference::createWithDisplacement(cg, dst, standingOffset+i*16, 16), fp1Reg);
11256
}
11257
11258
if ((residue64 & 0xF) != 0)
11259
{
11260
standingOffset += residue64 & 0x30;
11261
switch (residue64 & 0xF)
11262
{
11263
case 1:
11264
generateTrg1MemInstruction(cg, TR::InstOpCode::lbz, node, tmp1Reg, TR::MemoryReference::createWithDisplacement(cg, src, standingOffset, 1));
11265
generateMemSrc1Instruction(cg, TR::InstOpCode::stb, node, TR::MemoryReference::createWithDisplacement(cg, dst, standingOffset, 1), tmp1Reg);
11266
break;
11267
case 2:
11268
generateTrg1MemInstruction(cg, TR::InstOpCode::lhz, node, tmp1Reg, TR::MemoryReference::createWithDisplacement(cg, src, standingOffset, 2));
11269
generateMemSrc1Instruction(cg, TR::InstOpCode::sth, node, TR::MemoryReference::createWithDisplacement(cg, dst, standingOffset, 2), tmp1Reg);
11270
break;
11271
case 4:
11272
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, tmp1Reg, TR::MemoryReference::createWithDisplacement(cg, src, standingOffset, 4));
11273
generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, dst, standingOffset, 4), tmp1Reg);
11274
break;
11275
case 8:
11276
generateTrg1MemInstruction(cg, TR::InstOpCode::ld, node, tmp1Reg, TR::MemoryReference::createWithDisplacement(cg, src, standingOffset, 8));
11277
generateMemSrc1Instruction(cg, TR::InstOpCode::std, node, TR::MemoryReference::createWithDisplacement(cg, dst, standingOffset, 8), tmp1Reg);
11278
break;
11279
default:
11280
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, tmp1Reg, residue64 & 0xF);
11281
generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicr, node, tmp1Reg, tmp1Reg,
11282
56, CONSTANT64(0xff00000000000000));
11283
if (standingOffset != 0)
11284
{
11285
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, src, src, standingOffset);
11286
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, dst, dst, standingOffset);
11287
}
11288
generateTrg1Src2Instruction(cg, TR::InstOpCode::lxvl, node, fp1Reg, src, tmp1Reg);
11289
generateSrc3Instruction(cg, TR::InstOpCode::stxvl, node, fp1Reg, dst, tmp1Reg);
11290
break;
11291
}
11292
}
11293
}
11294
else
11295
{
11296
TR::Register *regs[4] = {tmp1Reg, tmp2Reg, tmp3Reg, tmp4Reg};
11297
TR::Register *fpRegs[4] = {fp1Reg, fp2Reg, fp3Reg, fp4Reg};
11298
int32_t groups, residual;
11299
11300
static bool disableLEArrayCopyInline = (feGetEnv("TR_disableLEArrayCopyInline") != NULL);
11301
bool supportsLEArrayCopyInline = cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P8) && !disableLEArrayCopyInline && cg->comp()->target().cpu.isLittleEndian() && cg->comp()->target().cpu.hasFPU() && cg->comp()->target().is64Bit();
11302
11303
if (cg->comp()->target().is64Bit())
11304
{
11305
groups = byteLen >> 5;
11306
residual = byteLen & 0x0000001F;
11307
}
11308
else
11309
{
11310
groups = byteLen >> 4;
11311
residual = byteLen & 0x0000000F;
11312
}
11313
11314
int32_t regIx = 0, ix = 0, fpRegIx = 0;
11315
int32_t memRefSize;
11316
TR::InstOpCode::Mnemonic load, store;
11317
TR::Compilation* comp = cg->comp();
11318
11319
/* Some machines have issues with 64bit loads/stores in 32bit mode, ie. sicily, do not check for is64BitProcessor() */
11320
memRefSize = TR::Compiler->om.sizeofReferenceAddress();
11321
load = TR::InstOpCode::Op_load;
11322
store = TR::InstOpCode::Op_st;
11323
11324
if (groups != 0)
11325
{
11326
TR::LabelSymbol *loopStart;
11327
11328
if (groups != 1)
11329
{
11330
if (groups <= UPPER_IMMED)
11331
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, regs[0], groups);
11332
else
11333
loadConstant(cg, node, groups, regs[0]);
11334
generateSrc1Instruction(cg, TR::InstOpCode::mtctr, node, regs[0]);
11335
11336
loopStart = generateLabelSymbol(cg);
11337
generateLabelInstruction(cg, TR::InstOpCode::label, node, loopStart);
11338
}
11339
11340
if (supportsLEArrayCopyInline)
11341
{
11342
generateTrg1MemInstruction(cg, TR::InstOpCode::lfd, node, fpRegs[3], TR::MemoryReference::createWithDisplacement(cg, src, 0, memRefSize));
11343
generateTrg1MemInstruction(cg, TR::InstOpCode::lfd, node, fpRegs[2], TR::MemoryReference::createWithDisplacement(cg, src, memRefSize, memRefSize));
11344
generateTrg1MemInstruction(cg, TR::InstOpCode::lfd, node, fpRegs[1], TR::MemoryReference::createWithDisplacement(cg, src, 2*memRefSize, memRefSize));
11345
generateTrg1MemInstruction(cg, TR::InstOpCode::lfd, node, fpRegs[0], TR::MemoryReference::createWithDisplacement(cg, src, 3*memRefSize, memRefSize));
11346
}
11347
else
11348
{
11349
generateTrg1MemInstruction(cg, load, node, regs[3], TR::MemoryReference::createWithDisplacement(cg, src, 0, memRefSize));
11350
generateTrg1MemInstruction(cg, load, node, regs[2], TR::MemoryReference::createWithDisplacement(cg, src, memRefSize, memRefSize));
11351
generateTrg1MemInstruction(cg, load, node, regs[1], TR::MemoryReference::createWithDisplacement(cg, src, 2*memRefSize, memRefSize));
11352
generateTrg1MemInstruction(cg, load, node, regs[0], TR::MemoryReference::createWithDisplacement(cg, src, 3*memRefSize, memRefSize));
11353
}
11354
11355
if (groups != 1)
11356
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi, node, src, src, 4*memRefSize);
11357
11358
if (supportsLEArrayCopyInline)
11359
{
11360
generateMemSrc1Instruction(cg, TR::InstOpCode::stfd, node, TR::MemoryReference::createWithDisplacement(cg, dst, 0, memRefSize), fpRegs[3]);
11361
generateMemSrc1Instruction(cg, TR::InstOpCode::stfd, node, TR::MemoryReference::createWithDisplacement(cg, dst, memRefSize, memRefSize), fpRegs[2]);
11362
generateMemSrc1Instruction(cg, TR::InstOpCode::stfd, node, TR::MemoryReference::createWithDisplacement(cg, dst, 2*memRefSize, memRefSize), fpRegs[1]);
11363
generateMemSrc1Instruction(cg, TR::InstOpCode::stfd, node, TR::MemoryReference::createWithDisplacement(cg, dst, 3*memRefSize, memRefSize), fpRegs[0]);
11364
}
11365
else
11366
{
11367
generateMemSrc1Instruction(cg, store, node, TR::MemoryReference::createWithDisplacement(cg, dst, 0, memRefSize), regs[3]);
11368
generateMemSrc1Instruction(cg, store, node, TR::MemoryReference::createWithDisplacement(cg, dst, memRefSize, memRefSize), regs[2]);
11369
generateMemSrc1Instruction(cg, store, node, TR::MemoryReference::createWithDisplacement(cg, dst, 2*memRefSize, memRefSize), regs[1]);
11370
generateMemSrc1Instruction(cg, store, node, TR::MemoryReference::createWithDisplacement(cg, dst, 3*memRefSize, memRefSize), regs[0]);
11371
}
11372
11373
if (groups != 1)
11374
{
11375
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2, node, dst, dst, 4*memRefSize);
11376
generateConditionalBranchInstruction(cg, TR::InstOpCode::bdnz, node, loopStart, cndReg);
11377
}
11378
else
11379
{
11380
ix = 4*memRefSize;
11381
}
11382
}
11383
11384
for (; residual>=memRefSize; residual-=memRefSize, ix+=memRefSize)
11385
{
11386
if (supportsLEArrayCopyInline)
11387
{
11388
TR::Register *oneReg = fpRegs[fpRegIx++];
11389
if (fpRegIx>3 || fpRegs[fpRegIx]==NULL)
11390
fpRegIx = 0;
11391
generateTrg1MemInstruction(cg, TR::InstOpCode::lfd, node, oneReg, TR::MemoryReference::createWithDisplacement(cg, src, ix, memRefSize));
11392
generateMemSrc1Instruction(cg, TR::InstOpCode::stfd, node, TR::MemoryReference::createWithDisplacement(cg, dst, ix, memRefSize), oneReg);
11393
}
11394
else
11395
{
11396
TR::Register *oneReg = regs[regIx++];
11397
if (regIx>3 || regs[regIx]==NULL)
11398
regIx = 0;
11399
generateTrg1MemInstruction(cg, load, node, oneReg, TR::MemoryReference::createWithDisplacement(cg, src, ix, memRefSize));
11400
generateMemSrc1Instruction(cg, store, node, TR::MemoryReference::createWithDisplacement(cg, dst, ix, memRefSize), oneReg);
11401
}
11402
}
11403
11404
if (residual != 0)
11405
{
11406
if (residual & 4)
11407
{
11408
if (supportsLEArrayCopyInline)
11409
{
11410
TR::Register *oneReg = fpRegs[fpRegIx++];
11411
if (fpRegIx>3 || fpRegs[fpRegIx]==NULL)
11412
fpRegIx = 0;
11413
generateTrg1MemInstruction(cg, TR::InstOpCode::lfs, node, oneReg, TR::MemoryReference::createWithDisplacement(cg, src, ix, 4));
11414
generateMemSrc1Instruction(cg, TR::InstOpCode::stfs, node, TR::MemoryReference::createWithDisplacement(cg, dst, ix, 4), oneReg);
11415
}
11416
else
11417
{
11418
TR::Register *oneReg = regs[regIx++];
11419
if (regIx>3 || regs[regIx]==NULL)
11420
regIx = 0;
11421
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, oneReg, TR::MemoryReference::createWithDisplacement(cg, src, ix, 4));
11422
generateMemSrc1Instruction(cg, TR::InstOpCode::stw, node, TR::MemoryReference::createWithDisplacement(cg, dst, ix, 4), oneReg);
11423
}
11424
ix += 4;
11425
}
11426
if (residual & 2)
11427
{
11428
TR::Register *oneReg = regs[regIx++];
11429
if (regIx>3 || regs[regIx]==NULL)
11430
regIx = 0;
11431
generateTrg1MemInstruction(cg, TR::InstOpCode::lhz, node, oneReg, TR::MemoryReference::createWithDisplacement(cg, src, ix, 2));
11432
generateMemSrc1Instruction(cg, TR::InstOpCode::sth, node, TR::MemoryReference::createWithDisplacement(cg, dst, ix, 2), oneReg);
11433
ix += 2;
11434
}
11435
if (residual & 1)
11436
{
11437
generateTrg1MemInstruction(cg, TR::InstOpCode::lbz, node, regs[regIx], TR::MemoryReference::createWithDisplacement(cg, src, ix, 1));
11438
generateMemSrc1Instruction(cg, TR::InstOpCode::stb, node, TR::MemoryReference::createWithDisplacement(cg, dst, ix, 1), regs[regIx]);
11439
}
11440
}
11441
}
11442
11443
return;
11444
}
11445
11446
bool
11447
J9::Power::CodeGenerator::inlineDirectCall(TR::Node *node, TR::Register *&resultReg)
11448
{
11449
TR::CodeGenerator *cg = self();
11450
TR::Compilation *comp = cg->comp();
11451
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());
11452
TR::MethodSymbol * methodSymbol = node->getSymbol()->getMethodSymbol();
11453
11454
static bool disableDCAS = (feGetEnv("TR_DisablePPCDCAS") != NULL);
11455
static bool useJapaneseCompression = (feGetEnv("TR_JapaneseComp") != NULL);
11456
11457
if (comp->getSymRefTab()->isNonHelper(node->getSymbolReference(), TR::SymbolReferenceTable::singlePrecisionSQRTSymbol))
11458
{
11459
resultReg = inlineSinglePrecisionFP(node, TR::InstOpCode::fsqrts, cg);
11460
return true;
11461
}
11462
else if (OMR::CodeGeneratorConnector::inlineDirectCall(node, resultReg))
11463
{
11464
return true;
11465
}
11466
else if (methodSymbol)
11467
{
11468
switch (methodSymbol->getRecognizedMethod())
11469
{
11470
case TR::java_util_concurrent_ConcurrentLinkedQueue_tmOffer:
11471
{
11472
if (cg->getSupportsInlineConcurrentLinkedQueue())
11473
{
11474
resultReg = inlineConcurrentLinkedQueueTMOffer(node, cg);
11475
return true;
11476
}
11477
break;
11478
}
11479
11480
case TR::java_util_concurrent_ConcurrentLinkedQueue_tmPoll:
11481
{
11482
if (cg->getSupportsInlineConcurrentLinkedQueue())
11483
{
11484
resultReg = inlineConcurrentLinkedQueueTMPoll(node, cg);
11485
return true;
11486
}
11487
break;
11488
}
11489
case TR::jdk_internal_misc_Unsafe_copyMemory0:
11490
case TR::sun_misc_Unsafe_copyMemory:
11491
if (comp->canTransformUnsafeCopyToArrayCopy()
11492
&& methodSymbol->isNative()
11493
&& performTransformation(comp,
11494
"O^O Call arraycopy instead of Unsafe.copyMemory: %s\n", cg->getDebug()->getName(node)))
11495
{
11496
TR::Node *src = node->getChild(1);
11497
TR::Node *srcOffset = node->getChild(2);
11498
TR::Node *dest = node->getChild(3);
11499
TR::Node *destOffset = node->getChild(4);
11500
TR::Node *len = node->getChild(5);
11501
11502
if (comp->target().is32Bit())
11503
{
11504
srcOffset = TR::Node::create(TR::l2i, 1, srcOffset);
11505
destOffset = TR::Node::create(TR::l2i, 1, destOffset);
11506
len = TR::Node::create(TR::l2i, 1, len);
11507
src = TR::Node::create(TR::aiadd, 2, src, srcOffset);
11508
dest = TR::Node::create(TR::aiadd, 2, dest, destOffset);
11509
}
11510
else
11511
{
11512
src = TR::Node::create(TR::aladd, 2, src, srcOffset);
11513
dest = TR::Node::create(TR::aladd, 2, dest, destOffset);
11514
}
11515
11516
TR::Node *arraycopyNode = TR::Node::createArraycopy(src, dest, len);
11517
TR::TreeEvaluator::arraycopyEvaluator(arraycopyNode,cg);
11518
11519
if (node->getChild(0)->getRegister())
11520
cg->decReferenceCount(node->getChild(0));
11521
else
11522
node->getChild(0)->recursivelyDecReferenceCount();
11523
11524
cg->decReferenceCount(node->getChild(1));
11525
cg->decReferenceCount(node->getChild(2));
11526
cg->decReferenceCount(node->getChild(3));
11527
cg->decReferenceCount(node->getChild(4));
11528
cg->decReferenceCount(node->getChild(5));
11529
11530
return true;
11531
}
11532
break;
11533
11534
case TR::sun_misc_Unsafe_setMemory:
11535
if (comp->canTransformUnsafeSetMemory())
11536
{
11537
TR::Node *dest = node->getChild(1);
11538
TR::Node *destOffset = node->getChild(2);
11539
TR::Node *len = node->getChild(3);
11540
TR::Node *byteValue = node->getChild(4);
11541
dest = TR::Node::create(TR::aladd, 2, dest, destOffset);
11542
11543
TR::Node * copyMemNode = TR::Node::createWithSymRef(TR::arrayset, 3, 3, dest, len, byteValue, node->getSymbolReference());
11544
copyMemNode->setByteCodeInfo(node->getByteCodeInfo());
11545
11546
TR::TreeEvaluator::setmemoryEvaluator(copyMemNode,cg);
11547
11548
if (node->getChild(0)->getRegister())
11549
cg->decReferenceCount(node->getChild(0));
11550
else
11551
node->getChild(0)->recursivelyDecReferenceCount();
11552
11553
cg->decReferenceCount(node->getChild(1));
11554
cg->decReferenceCount(node->getChild(2));
11555
cg->decReferenceCount(node->getChild(3));
11556
cg->decReferenceCount(node->getChild(4));
11557
return true;
11558
}
11559
break;
11560
11561
case TR::java_lang_String_compress:
11562
resultReg = compressStringEvaluator(node, cg, useJapaneseCompression);
11563
return true;
11564
break;
11565
11566
case TR::java_lang_String_compressNoCheck:
11567
resultReg = compressStringNoCheckEvaluator(node, cg, useJapaneseCompression);
11568
return true;
11569
11570
case TR::java_lang_String_andOR:
11571
resultReg = andORStringEvaluator(node, cg);
11572
return true;
11573
break;
11574
11575
case TR::java_util_concurrent_atomic_AtomicBoolean_getAndSet:
11576
case TR::java_util_concurrent_atomic_AtomicInteger_getAndAdd:
11577
case TR::java_util_concurrent_atomic_AtomicInteger_getAndIncrement:
11578
case TR::java_util_concurrent_atomic_AtomicInteger_getAndDecrement:
11579
case TR::java_util_concurrent_atomic_AtomicInteger_getAndSet:
11580
case TR::java_util_concurrent_atomic_AtomicInteger_addAndGet:
11581
case TR::java_util_concurrent_atomic_AtomicInteger_incrementAndGet:
11582
case TR::java_util_concurrent_atomic_AtomicInteger_decrementAndGet:
11583
{
11584
resultReg = inlineAtomicOps(node, cg, 4, methodSymbol, false);
11585
return true;
11586
break;
11587
}
11588
11589
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndAdd:
11590
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndIncrement:
11591
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndDecrement:
11592
case TR::java_util_concurrent_atomic_AtomicIntegerArray_getAndSet:
11593
case TR::java_util_concurrent_atomic_AtomicIntegerArray_addAndGet:
11594
case TR::java_util_concurrent_atomic_AtomicIntegerArray_incrementAndGet:
11595
case TR::java_util_concurrent_atomic_AtomicIntegerArray_decrementAndGet:
11596
{
11597
resultReg = inlineAtomicOps(node, cg, 4, methodSymbol, true);
11598
return true;
11599
break;
11600
}
11601
11602
case TR::java_lang_Math_ceil:
11603
case TR::java_lang_StrictMath_ceil:
11604
if (methodSymbol->getResolvedMethodSymbol()->canReplaceWithHWInstr())
11605
{
11606
resultReg = inlineDoublePrecisionFP(node, TR::InstOpCode::frip, cg);
11607
return true;
11608
}
11609
break;
11610
11611
case TR::java_lang_Math_floor:
11612
case TR::java_lang_StrictMath_floor:
11613
if (methodSymbol->getResolvedMethodSymbol()->canReplaceWithHWInstr())
11614
{
11615
resultReg = inlineDoublePrecisionFP(node, TR::InstOpCode::frim, cg);
11616
return true;
11617
}
11618
break;
11619
11620
case TR::java_lang_Math_copySign_F:
11621
// StrictMath copySign spec not guaranteed by fcpsgn instruction
11622
if (methodSymbol->getResolvedMethodSymbol()->canReplaceWithHWInstr())
11623
{
11624
resultReg = inlineSinglePrecisionFPTrg1Src2(node, TR::InstOpCode::fcpsgn, cg);
11625
return true;
11626
}
11627
break;
11628
11629
case TR::java_lang_Math_copySign_D:
11630
// StrictMath copySign spec not guaranteed by fcpsgn instruction
11631
if (methodSymbol->getResolvedMethodSymbol()->canReplaceWithHWInstr())
11632
{
11633
resultReg = inlineDoublePrecisionFPTrg1Src2(node, TR::InstOpCode::fcpsgn, cg);
11634
return true;
11635
}
11636
break;
11637
11638
case TR::java_lang_Math_fma_D:
11639
case TR::java_lang_StrictMath_fma_D:
11640
resultReg = inlineFPTrg1Src3(node, TR::InstOpCode::fmadd, cg);
11641
return true;
11642
11643
case TR::java_lang_Math_fma_F:
11644
case TR::java_lang_StrictMath_fma_F:
11645
resultReg = inlineFPTrg1Src3(node, TR::InstOpCode::fmadds, cg);
11646
return true;
11647
11648
case TR::java_lang_String_hashCodeImplDecompressed:
11649
if (!TR::Compiler->om.canGenerateArraylets() && comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P8) && comp->target().cpu.supportsFeature(OMR_FEATURE_PPC_HAS_VSX) && !comp->compileRelocatableCode()
11650
#ifdef J9VM_OPT_JITSERVER
11651
&& !comp->isOutOfProcessCompilation()
11652
#endif
11653
)
11654
{
11655
resultReg = inlineStringHashcode(node, cg);
11656
return true;
11657
}
11658
break;
11659
11660
case TR::com_ibm_jit_JITHelpers_transformedEncodeUTF16Big:
11661
case TR::com_ibm_jit_JITHelpers_transformedEncodeUTF16Little:
11662
if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P7) && comp->target().cpu.supportsFeature(OMR_FEATURE_PPC_HAS_VSX))
11663
{
11664
resultReg = inlineEncodeUTF16(node, cg);
11665
return true;
11666
}
11667
break;
11668
11669
case TR::com_ibm_jit_JITHelpers_intrinsicIndexOfLatin1:
11670
case TR::com_ibm_jit_JITHelpers_intrinsicIndexOfUTF16:
11671
if (cg->getSupportsInlineStringIndexOf())
11672
{
11673
bool isLatin1 = methodSymbol->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_intrinsicIndexOfLatin1;
11674
if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10))
11675
resultReg = inlineIntrinsicIndexOf_P10(node, cg, isLatin1);
11676
else
11677
resultReg = inlineIntrinsicIndexOf(node, cg, isLatin1);
11678
return resultReg != nullptr;
11679
}
11680
break;
11681
11682
case TR::sun_misc_Unsafe_compareAndSwapInt_jlObjectJII_Z:
11683
// In Java9 this can be either the jdk.internal JNI method or the sun.misc Java wrapper.
11684
// In Java8 it will be sun.misc which will contain the JNI directly.
11685
// We only want to inline the JNI methods, so add an explicit test for isNative().
11686
if (!methodSymbol->isNative())
11687
break;
11688
11689
if ((node->isUnsafeGetPutCASCallOnNonArray() || !TR::Compiler->om.canGenerateArraylets()) && node->isSafeForCGToFastPathUnsafeCall())
11690
{
11691
resultReg = VMinlineCompareAndSwap(node, cg, false);
11692
return true;
11693
}
11694
break;
11695
11696
case TR::sun_misc_Unsafe_compareAndSwapLong_jlObjectJJJ_Z:
11697
if (comp->getOption(TR_TraceCG))
11698
traceMsg(comp, "In evaluator for compareAndSwapLong. node = %p node->isSafeForCGToFastPathUnsafeCall = %p\n", node, node->isSafeForCGToFastPathUnsafeCall());
11699
// As above, we only want to inline the JNI methods, so add an explicit test for isNative()
11700
if (!methodSymbol->isNative())
11701
break;
11702
11703
if (comp->target().is64Bit() && (node->isUnsafeGetPutCASCallOnNonArray() || !TR::Compiler->om.canGenerateArraylets()) && node->isSafeForCGToFastPathUnsafeCall())
11704
{
11705
resultReg = VMinlineCompareAndSwap(node, cg, true);
11706
return true;
11707
}
11708
else if ((node->isUnsafeGetPutCASCallOnNonArray() || !TR::Compiler->om.canGenerateArraylets()) && node->isSafeForCGToFastPathUnsafeCall())
11709
{
11710
resultReg = inlineAtomicOperation(node, cg, methodSymbol);
11711
return true;
11712
}
11713
break;
11714
11715
case TR::sun_misc_Unsafe_compareAndSwapObject_jlObjectJjlObjectjlObject_Z:
11716
// As above, we only want to inline the JNI methods, so add an explicit test for isNative()
11717
if (!methodSymbol->isNative())
11718
break;
11719
11720
if ((node->isUnsafeGetPutCASCallOnNonArray() || !TR::Compiler->om.canGenerateArraylets()) && node->isSafeForCGToFastPathUnsafeCall())
11721
{
11722
resultReg = VMinlineCompareAndSwapObject(node, cg);
11723
return true;
11724
}
11725
break;
11726
11727
case TR::java_nio_Bits_keepAlive:
11728
case TR::java_lang_ref_Reference_reachabilityFence:
11729
{
11730
TR::Node *paramNode = node->getFirstChild();
11731
TR::Register *paramReg = cg->evaluate(paramNode);
11732
TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(1, 1, cg->trMemory());
11733
TR::addDependency(conditions, paramReg, TR::RealRegister::NoReg, TR_GPR, cg);
11734
TR::LabelSymbol *label = TR::LabelSymbol::create(cg->trHeapMemory(),cg);
11735
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, label, conditions);
11736
cg->decReferenceCount(paramNode);
11737
resultReg = NULL;
11738
return true;
11739
}
11740
11741
case TR::x10JITHelpers_getCPU:
11742
break;
11743
11744
case TR::java_util_concurrent_atomic_Fences_reachabilityFence:
11745
{
11746
cg->decReferenceCount(node->getChild(0));
11747
resultReg = NULL;
11748
return true;
11749
}
11750
11751
case TR::java_util_concurrent_atomic_Fences_orderReads:
11752
if (performTransformation(comp, "O^O PPC Evaluator: Replacing read/read Fence with an lwsync [%p].\n", node))
11753
{
11754
// mark as seen and then just don't bother generating instructions
11755
TR::Node *callNode = node;
11756
int32_t numArgs = callNode->getNumChildren();
11757
for (int32_t i = numArgs - 1; i >= 0; i--)
11758
cg->decReferenceCount(callNode->getChild(i));
11759
cg->decReferenceCount(callNode);
11760
generateInstruction(cg, TR::InstOpCode::isync, node);
11761
resultReg = NULL;
11762
return true;
11763
}
11764
break;
11765
11766
// for now all preStores simply emit lwsync See JIT design 1598
11767
case TR::java_util_concurrent_atomic_Fences_preStoreFence:
11768
case TR::java_util_concurrent_atomic_Fences_preStoreFence_jlObject:
11769
case TR::java_util_concurrent_atomic_Fences_preStoreFence_jlObjectI:
11770
case TR::java_util_concurrent_atomic_Fences_preStoreFence_jlObjectjlrField:
11771
case TR::java_util_concurrent_atomic_Fences_postLoadFence:
11772
case TR::java_util_concurrent_atomic_Fences_postLoadFence_jlObjectjlrField:
11773
case TR::java_util_concurrent_atomic_Fences_postLoadFence_jlObject:
11774
case TR::java_util_concurrent_atomic_Fences_postLoadFence_jlObjectI:
11775
case TR::java_util_concurrent_atomic_Fences_orderWrites:
11776
if (performTransformation(comp, "O^O PPC Evaluator: Replacing store/store Fence with an lwsync [%p].\n", node))
11777
{
11778
// mark as seen and then just don't bother generating instructions
11779
TR::Node *callNode = node;
11780
int32_t numArgs = callNode->getNumChildren();
11781
for (int32_t i = numArgs - 1; i >= 0; i--)
11782
cg->decReferenceCount(callNode->getChild(i));
11783
cg->decReferenceCount(callNode);
11784
generateInstruction(cg, TR::InstOpCode::lwsync, node);
11785
resultReg = NULL;
11786
return true;
11787
}
11788
break;
11789
11790
// for now just emit a sync. See design 1598
11791
case TR::java_util_concurrent_atomic_Fences_postStorePreLoadFence_jlObject:
11792
case TR::java_util_concurrent_atomic_Fences_postStorePreLoadFence_jlObjectjlrField:
11793
case TR::java_util_concurrent_atomic_Fences_postStorePreLoadFence:
11794
case TR::java_util_concurrent_atomic_Fences_postStorePreLoadFence_jlObjectI:
11795
case TR::java_util_concurrent_atomic_Fences_orderAccesses:
11796
if (performTransformation(comp, "O^O PPC Evaluator: Replacing store/load Fence with a sync [%p].\n", node))
11797
{
11798
TR::Node *callNode = node;
11799
int32_t numArgs = callNode->getNumChildren();
11800
for (int32_t i = numArgs - 1; i >= 0; i--)
11801
cg->decReferenceCount(callNode->getChild(i));
11802
cg->decReferenceCount(callNode);
11803
generateInstruction(cg, TR::InstOpCode::sync, node);
11804
resultReg = NULL;
11805
return true;
11806
}
11807
break;
11808
11809
case TR::java_lang_Class_isAssignableFrom:
11810
{
11811
// Do not use an inline class check if the 'this' Class object is known to be an
11812
// abstract class or an interface at compile-time (the check will always fail
11813
// and go out of line).
11814
//
11815
TR::Node *receiverNode = node->getFirstChild();
11816
if (receiverNode->getOpCodeValue() == TR::aloadi &&
11817
receiverNode->getSymbolReference() == comp->getSymRefTab()->findJavaLangClassFromClassSymbolRef() &&
11818
receiverNode->getFirstChild()->getOpCodeValue() == TR::loadaddr)
11819
{
11820
TR::SymbolReference *receiverClassSymRef = receiverNode->getFirstChild()->getSymbolReference();
11821
if (receiverClassSymRef->isClassInterface(comp) ||
11822
receiverClassSymRef->isClassAbstract(comp))
11823
break;
11824
}
11825
11826
static bool disable = feGetEnv("TR_disableInlineIsAssignableFrom") != NULL;
11827
if (!disable &&
11828
performTransformation(comp, "O^O PPC Evaluator: Specialize call to java/lang/Class.isAssignableFrom [%p].\n", node))
11829
{
11830
resultReg = inlineIsAssignableFrom(node, cg);
11831
return true;
11832
}
11833
11834
break;
11835
}
11836
11837
default:
11838
break;
11839
}
11840
}
11841
11842
#ifdef J9VM_OPT_JAVA_CRYPTO_ACCELERATION
11843
if (self()->inlineCryptoMethod(node, resultReg))
11844
{
11845
return true;
11846
}
11847
#endif
11848
11849
// No method specialization was done.
11850
//
11851
resultReg = NULL;
11852
return false;
11853
}
11854
11855
void VMgenerateCatchBlockBBStartPrologue(TR::Node *node, TR::Instruction *fenceInstruction, TR::CodeGenerator *cg)
11856
{
11857
TR::Compilation *comp = cg->comp();
11858
TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());
11859
11860
TR::Block *block = node->getBlock();
11861
11862
if (fej9->shouldPerformEDO(block, comp))
11863
{
11864
TR::Register *biAddrReg = cg->allocateRegister();
11865
TR::Register *recompCounterReg = cg->allocateRegister();
11866
intptr_t addr = (intptr_t) (comp->getRecompilationInfo()->getCounterAddress());
11867
TR::Instruction *cursor = loadAddressConstant(cg, comp->compileRelocatableCode(), node, addr, biAddrReg);
11868
TR::MemoryReference *loadbiMR = TR::MemoryReference::createWithDisplacement(cg, biAddrReg, 0, TR::Compiler->om.sizeofReferenceAddress());
11869
TR::MemoryReference *storebiMR = TR::MemoryReference::createWithDisplacement(cg, biAddrReg, 0, TR::Compiler->om.sizeofReferenceAddress());
11870
cursor = generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, recompCounterReg, loadbiMR);
11871
TR::Register *cndRegister = cg->allocateRegister(TR_CCR);
11872
cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::addi2_r, node, recompCounterReg, recompCounterReg, cndRegister, -1, cursor);
11873
cursor = generateMemSrc1Instruction(cg,TR::InstOpCode::Op_st, node, storebiMR, recompCounterReg, cursor);
11874
cg->stopUsingRegister(biAddrReg);
11875
cg->stopUsingRegister(recompCounterReg);
11876
11877
TR::LabelSymbol *snippetLabel = NULL;
11878
TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);
11879
// snippet call chain through jitCallCFunction kills 3 parameter
11880
// registers that we will reserve here
11881
TR::Register *arg1Reg, *arg2Reg, *arg3Reg;
11882
arg1Reg = cg->allocateRegister();
11883
arg2Reg = cg->allocateRegister();
11884
arg3Reg = cg->allocateRegister();
11885
11886
snippetLabel = cg->lookUpSnippet(TR::Snippet::IsForceRecompilation, NULL);
11887
if (snippetLabel == NULL)
11888
{
11889
TR::Snippet *snippet;
11890
snippetLabel = generateLabelSymbol(cg);
11891
snippet = new (cg->trHeapMemory()) TR::PPCForceRecompilationSnippet(snippetLabel, doneLabel, cursor, cg);
11892
cg->addSnippet(snippet);
11893
}
11894
11895
TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(4, 4, cg->trMemory());
11896
TR::addDependency(conditions, arg1Reg, TR::RealRegister::gr3, TR_GPR, cg);
11897
TR::addDependency(conditions, arg2Reg, TR::RealRegister::gr4, TR_GPR, cg);
11898
TR::addDependency(conditions, arg3Reg, TR::RealRegister::gr5, TR_GPR, cg);
11899
TR::addDependency(conditions, cndRegister, TR::RealRegister::cr0, TR_CCR, cg);
11900
11901
// used to be blel
11902
// only need to call snippet once, so using beql instead
11903
cursor = generateConditionalBranchInstruction(cg, TR::InstOpCode::beql, node, snippetLabel, cndRegister);
11904
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);
11905
11906
cg->machine()->setLinkRegisterKilled(true);
11907
conditions->stopUsingDepRegs(cg);
11908
}
11909
}
11910
11911
TR::Instruction *loadAddressRAM32(TR::CodeGenerator *cg, TR::Node * node, int32_t value, TR::Register *trgReg)
11912
{
11913
// load a 32-bit constant into a register with a fixed 2 instruction sequence
11914
TR::Compilation *comp = cg->comp();
11915
TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());
11916
11917
bool isAOT = comp->compileRelocatableCode();
11918
11919
TR::Instruction *cursor = cg->getAppendInstruction();
11920
11921
cursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, node, trgReg, isAOT ? 0 : value>>16, cursor);
11922
11923
if (value != 0x0)
11924
{
11925
TR_ExternalRelocationTargetKind reloType;
11926
if (node->getSymbol()->castToResolvedMethodSymbol()->isSpecial())
11927
reloType = TR_SpecialRamMethodConst;
11928
else if (node->getSymbol()->castToResolvedMethodSymbol()->isStatic())
11929
reloType = TR_StaticRamMethodConst;
11930
else if (node->getSymbol()->castToResolvedMethodSymbol()->isVirtual())
11931
reloType = TR_VirtualRamMethodConst;
11932
else
11933
{
11934
reloType = TR_NoRelocation;
11935
TR_ASSERT(0,"JNI relocation not supported.");
11936
}
11937
if(isAOT)
11938
cg->addExternalRelocation(new (cg->trHeapMemory()) TR::BeforeBinaryEncodingExternalRelocation(cursor, (uint8_t *) node->getSymbolReference(),
11939
node ? (uint8_t *)(intptr_t)node->getInlinedSiteIndex() : (uint8_t *)-1,
11940
reloType, cg),
11941
__FILE__, __LINE__, node);
11942
}
11943
11944
cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, trgReg, trgReg, isAOT ? 0 : value&0x0000ffff, cursor);
11945
11946
cg->setAppendInstruction(cursor);
11947
return(cursor);
11948
}
11949
11950
TR::Instruction *loadAddressRAM(TR::CodeGenerator *cg, TR::Node * node, intptr_t value, TR::Register *trgReg)
11951
{
11952
TR::Compilation *comp = cg->comp();
11953
TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());
11954
bool isAOT = comp->compileRelocatableCode();
11955
if (comp->target().is32Bit())
11956
{
11957
return loadAddressRAM32(cg, node, (int32_t)value, trgReg);
11958
}
11959
11960
// load a 64-bit constant into a register with a fixed 5 instruction sequence
11961
TR::Instruction *cursor = cg->getAppendInstruction();
11962
11963
// lis trgReg, upper 16-bits
11964
cursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, node, trgReg, isAOT? 0: (value>>48) , cursor);
11965
if (value != 0x0)
11966
{
11967
TR_ExternalRelocationTargetKind reloType;
11968
if (node->getSymbol()->castToResolvedMethodSymbol()->isSpecial())
11969
reloType = TR_SpecialRamMethodConst;
11970
else if (node->getSymbol()->castToResolvedMethodSymbol()->isStatic())
11971
reloType = TR_StaticRamMethodConst;
11972
else if (node->getSymbol()->castToResolvedMethodSymbol()->isVirtual())
11973
reloType = TR_VirtualRamMethodConst;
11974
else
11975
{
11976
reloType = TR_NoRelocation;
11977
TR_ASSERT(0,"JNI relocation not supported.");
11978
}
11979
if(isAOT)
11980
cg->addExternalRelocation(new (cg->trHeapMemory()) TR::BeforeBinaryEncodingExternalRelocation(cursor, (uint8_t *) node->getSymbolReference(),
11981
node ? (uint8_t *)(intptr_t)node->getInlinedSiteIndex() : (uint8_t *)-1,
11982
reloType, cg),
11983
__FILE__,__LINE__, node);
11984
}
11985
// ori trgReg, trgReg, next 16-bits
11986
cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, trgReg, trgReg, isAOT ? 0 : ((value>>32) & 0x0000ffff), cursor);
11987
// shiftli trgReg, trgReg, 32
11988
cursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicr, node, trgReg, trgReg, 32, CONSTANT64(0xFFFFFFFF00000000), cursor);
11989
// oris trgReg, trgReg, next 16-bits
11990
cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::oris, node, trgReg, trgReg, isAOT ? 0 : ((value>>16) & 0x0000ffff), cursor);
11991
// ori trgReg, trgReg, last 16-bits
11992
cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, trgReg, trgReg, isAOT ? 0 : (value & 0x0000ffff), cursor);
11993
11994
cg->setAppendInstruction(cursor);
11995
11996
return(cursor);
11997
}
11998
11999
TR::Instruction *loadAddressJNI32(TR::CodeGenerator *cg, TR::Node * node, int32_t value, TR::Register *trgReg)
12000
{
12001
// load a 32-bit constant into a register with a fixed 2 instruction sequence
12002
TR::Compilation *comp = cg->comp();
12003
TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());
12004
12005
bool isAOT = comp->compileRelocatableCode();
12006
12007
TR::Instruction *cursor = cg->getAppendInstruction();
12008
12009
cursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, node, trgReg, isAOT ? 0 : value>>16, cursor);
12010
12011
if (isAOT && value != 0x0)
12012
{
12013
TR_ExternalRelocationTargetKind reloType;
12014
if (node->getSymbol()->castToResolvedMethodSymbol()->isSpecial())
12015
reloType = TR_JNISpecialTargetAddress;
12016
else if (node->getSymbol()->castToResolvedMethodSymbol()->isStatic())
12017
reloType = TR_JNIStaticTargetAddress;
12018
else if (node->getSymbol()->castToResolvedMethodSymbol()->isVirtual())
12019
reloType = TR_JNIVirtualTargetAddress;
12020
else
12021
{
12022
reloType = TR_NoRelocation;
12023
TR_ASSERT(0,"JNI relocation not supported.");
12024
}
12025
12026
TR_RelocationRecordInformation *info = new (comp->trHeapMemory()) TR_RelocationRecordInformation();
12027
info->data1 = 0;
12028
info->data2 = reinterpret_cast<uintptr_t>(node->getSymbolReference());
12029
int16_t inlinedSiteIndex = node ? node->getInlinedSiteIndex() : -1;
12030
info->data3 = static_cast<uintptr_t>(inlinedSiteIndex);
12031
12032
cg->addExternalRelocation(
12033
new (cg->trHeapMemory()) TR::BeforeBinaryEncodingExternalRelocation(
12034
cursor,
12035
reinterpret_cast<uint8_t *>(info),
12036
reloType,
12037
cg),
12038
__FILE__, __LINE__, node);
12039
}
12040
12041
cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, trgReg, trgReg, isAOT ? 0 : value&0x0000ffff, cursor);
12042
12043
cg->setAppendInstruction(cursor);
12044
return(cursor);
12045
}
12046
12047
TR::Instruction *loadAddressJNI(TR::CodeGenerator *cg, TR::Node * node, intptr_t value, TR::Register *trgReg)
12048
{
12049
TR::Compilation *comp = cg->comp();
12050
TR_J9VMBase *fej9 = (TR_J9VMBase *) (comp->fe());
12051
bool isAOT = comp->compileRelocatableCode();
12052
if (comp->target().is32Bit())
12053
{
12054
return loadAddressJNI32(cg, node, (int32_t)value, trgReg);
12055
}
12056
12057
// load a 64-bit constant into a register with a fixed 5 instruction sequence
12058
TR::Instruction *cursor = cg->getAppendInstruction();
12059
12060
// lis trgReg, upper 16-bits
12061
cursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::lis, node, trgReg, isAOT? 0: (value>>48) , cursor);
12062
if (isAOT && value != 0x0)
12063
{
12064
TR_ExternalRelocationTargetKind reloType;
12065
if (node->getSymbol()->castToResolvedMethodSymbol()->isSpecial())
12066
reloType = TR_JNISpecialTargetAddress;
12067
else if (node->getSymbol()->castToResolvedMethodSymbol()->isStatic())
12068
reloType = TR_JNIStaticTargetAddress;
12069
else if (node->getSymbol()->castToResolvedMethodSymbol()->isVirtual())
12070
reloType = TR_JNIVirtualTargetAddress;
12071
else
12072
{
12073
reloType = TR_NoRelocation;
12074
TR_ASSERT(0,"JNI relocation not supported.");
12075
}
12076
12077
TR_RelocationRecordInformation *info = new (comp->trHeapMemory()) TR_RelocationRecordInformation();
12078
info->data1 = 0;
12079
info->data2 = reinterpret_cast<uintptr_t>(node->getSymbolReference());
12080
int16_t inlinedSiteIndex = node ? node->getInlinedSiteIndex() : -1;
12081
info->data3 = static_cast<uintptr_t>(inlinedSiteIndex);
12082
12083
cg->addExternalRelocation(
12084
new (cg->trHeapMemory()) TR::BeforeBinaryEncodingExternalRelocation(
12085
cursor,
12086
reinterpret_cast<uint8_t *>(info),
12087
reloType,
12088
cg),
12089
__FILE__, __LINE__, node);
12090
}
12091
// ori trgReg, trgReg, next 16-bits
12092
cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, trgReg, trgReg, isAOT ? 0 : ((value>>32) & 0x0000ffff), cursor);
12093
// shiftli trgReg, trgReg, 32
12094
cursor = generateTrg1Src1Imm2Instruction(cg, TR::InstOpCode::rldicr, node, trgReg, trgReg, 32, CONSTANT64(0xFFFFFFFF00000000), cursor);
12095
// oris trgReg, trgReg, next 16-bits
12096
cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::oris, node, trgReg, trgReg, isAOT ? 0 : ((value>>16) & 0x0000ffff), cursor);
12097
// ori trgReg, trgReg, last 16-bits
12098
cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ori, node, trgReg, trgReg, isAOT ? 0 : (value & 0x0000ffff), cursor);
12099
12100
cg->setAppendInstruction(cursor);
12101
12102
return(cursor);
12103
}
12104
12105
TR::Register *J9::Power::TreeEvaluator::directCallEvaluator(TR::Node *node, TR::CodeGenerator *cg)
12106
{
12107
TR::SymbolReference *symRef = node->getSymbolReference();
12108
TR::MethodSymbol *callee = symRef->getSymbol()->castToMethodSymbol();
12109
TR::Linkage *linkage;
12110
TR::Register *returnRegister;
12111
12112
if (callee->getRecognizedMethod() == TR::jdk_incubator_vector_FloatVector_add &&
12113
node->getOpCodeValue() == TR::vcall) // was vectorized
12114
{
12115
TR::Node::recreate(node, TR::vadd);
12116
return vaddEvaluator(node, cg);
12117
}
12118
else if (callee->getRecognizedMethod() == TR::jdk_internal_vm_vector_VectorSupport_binaryOp &&
12119
node->getOpCodeValue() == TR::vcall) // was vectorized
12120
{
12121
// The following code is temporary and can only be enabled for specific opcodes in VectorAPIExpansion.
12122
// It's an example of how development of vector evaluators can proceed until vector IL opcodes
12123
// are implemented. Eventually, all recognition of Vector API methods will be removed from this
12124
// evaluator
12125
//
12126
int firstOperandIndex = 5;
12127
int secondOperandIndex = 6;
12128
TR::Node *opcodeNode = node->getChild(0);
12129
TR::Node *dataTypeNode = node->getChild(3);
12130
TR::Node *numLanesNode = node->getChild(4);
12131
TR::Node *firstOperandNode = node->getChild(firstOperandIndex);
12132
TR::Node *secondOperandNode = node->getChild(secondOperandIndex);
12133
12134
TR::DataType dataType = TR_VectorAPIExpansion::getDataTypeFromClassNode(cg->comp(), dataTypeNode);
12135
bool supported = true;
12136
if (dataType != TR::Float)
12137
supported = false;
12138
if (!opcodeNode->getOpCode().isLoadConst() ||
12139
opcodeNode->getInt() != TR_VectorAPIExpansion::VECTOR_OP_ADD)
12140
supported = false;
12141
if (!numLanesNode->getOpCode().isLoadConst() ||
12142
numLanesNode->getInt() != 4)
12143
supported = false;
12144
12145
TR_ASSERT_FATAL_WITH_NODE(node, supported, "Vector API opcode, type, and number of lanes should be supported\n");
12146
12147
// evaluate unused children
12148
for (int i = 0; i < node->getNumChildren(); i++)
12149
{
12150
TR::Node *child = node->getChild(i);
12151
if (i != firstOperandIndex && i != secondOperandIndex)
12152
{
12153
cg->evaluate(child);
12154
cg->recursivelyDecReferenceCount(child);
12155
}
12156
}
12157
12158
node->setChild(0, firstOperandNode);
12159
node->setChild(1, secondOperandNode);
12160
node->setNumChildren(2);
12161
TR::Node::recreate(node, TR::vadd);
12162
return vaddEvaluator(node, cg);
12163
}
12164
else if (callee->getRecognizedMethod() >= TR::FirstVectorMethod &&
12165
callee->getRecognizedMethod() <= TR::LastVectorMethod &&
12166
node->getOpCodeValue() == TR::vcall) // was vectorized
12167
{
12168
TR_ASSERT_FATAL_WITH_NODE(node, false, "vcall is not supported for this Vector API method yet\n");
12169
}
12170
12171
12172
if (!cg->inlineDirectCall(node, returnRegister))
12173
{
12174
TR::SymbolReferenceTable *symRefTab = cg->comp()->getSymRefTab();
12175
12176
// Non-helpers supported by code gen. are expected to be inlined
12177
if (symRefTab->isNonHelper(symRef))
12178
{
12179
TR_ASSERT(!cg->supportsNonHelper(symRefTab->getNonHelperSymbol(symRef)),
12180
"Non-helper %d was not inlined, but was expected to be.\n",
12181
symRefTab->getNonHelperSymbol(symRef));
12182
}
12183
12184
linkage = cg->deriveCallingLinkage(node, false);
12185
returnRegister = linkage->buildDirectDispatch(node);
12186
}
12187
12188
return returnRegister;
12189
}
12190
12191
12192
TR::Register *J9::Power::TreeEvaluator::tstartEvaluator(TR::Node *node, TR::CodeGenerator *cg)
12193
{
12194
// tstart
12195
// - persistentFailNode
12196
// - transientFailNode
12197
// - fallThroughNode (next block)
12198
// - monitorObject
12199
//fprintf(stderr,"tstart Start\n");
12200
TR::Node *persistentFailureNode = node->getFirstChild();
12201
TR::Node *transientFailureNode = node->getSecondChild();
12202
TR::Node *fallThrough = node->getThirdChild();
12203
TR::Node *objNode = node->getChild(3);
12204
TR::Node *GRANode = NULL;
12205
TR::Compilation *comp = cg->comp();
12206
12207
TR::LabelSymbol *labelPersistentFailure = persistentFailureNode->getBranchDestination()->getNode()->getLabel();
12208
TR::LabelSymbol *labelTransientFailure = transientFailureNode->getBranchDestination()->getNode()->getLabel();
12209
TR::LabelSymbol *labelfallThrough = fallThrough->getBranchDestination()->getNode()->getLabel();
12210
TR::LabelSymbol *startLabel = generateLabelSymbol(cg);
12211
TR::LabelSymbol *lockwordLabel = generateLabelSymbol(cg);
12212
TR::LabelSymbol *noTexStatsLabel = generateLabelSymbol(cg);
12213
12214
TR::Register *objReg = cg->evaluate(objNode);
12215
TR::Register *monReg = cg->allocateRegister();
12216
TR::Register *cndReg = cg->allocateRegister(TR_CCR);
12217
TR::Register *tempReg = cg->allocateRegister();
12218
//TR::Register *temp2Reg = cg->allocateRegister();
12219
//TR::Register *temp3Reg = cg->allocateRegister();
12220
12221
// Dependency conditions for this evaluator's internal control flow
12222
TR::RegisterDependencyConditions *conditions = NULL;
12223
// Dependency conditions for GRA
12224
TR::RegisterDependencyConditions *fallThroughConditions = NULL;
12225
TR::RegisterDependencyConditions *persistentConditions = NULL;
12226
TR::RegisterDependencyConditions *transientConditions = NULL;
12227
12228
conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(4, 4, cg->trMemory());
12229
12230
if (fallThrough->getNumChildren() != 0)
12231
{
12232
GRANode = fallThrough->getFirstChild();
12233
cg->evaluate(GRANode);
12234
fallThroughConditions = generateRegisterDependencyConditions(cg, GRANode, 0);
12235
cg->decReferenceCount(GRANode);
12236
}
12237
12238
if (persistentFailureNode->getNumChildren() != 0)
12239
{
12240
GRANode = persistentFailureNode->getFirstChild();
12241
cg->evaluate(GRANode);
12242
persistentConditions = generateRegisterDependencyConditions(cg, GRANode, 0);
12243
cg->decReferenceCount(GRANode);
12244
}
12245
12246
if (transientFailureNode->getNumChildren() != 0)
12247
{
12248
GRANode = transientFailureNode->getFirstChild();
12249
cg->evaluate(GRANode);
12250
transientConditions = generateRegisterDependencyConditions(cg, GRANode, 0);
12251
cg->decReferenceCount(GRANode);
12252
}
12253
12254
uint32_t conditionCursor = conditions->getAddCursorForPre();
12255
TR::addDependency(conditions, objReg, TR::RealRegister::NoReg, TR_GPR, cg);
12256
conditions->getPreConditions()->getRegisterDependency(conditionCursor)->setExcludeGPR0();
12257
conditions->getPostConditions()->getRegisterDependency(conditionCursor++)->setExcludeGPR0();
12258
TR::addDependency(conditions, cndReg, TR::RealRegister::cr0, TR_CCR, cg);
12259
TR::addDependency(conditions, monReg, TR::RealRegister::NoReg, TR_GPR, cg);
12260
TR::addDependency(conditions, tempReg, TR::RealRegister::NoReg, TR_GPR, cg);
12261
12262
static char * debugTMTLE = feGetEnv("debugTMTLE");
12263
12264
if (debugTMTLE)
12265
printf ("\nTM: use TM TLE in %s (%s) %p", comp->signature(), comp->getHotnessName(comp->getMethodHotness()), node);
12266
12267
if (debugTMTLE )
12268
{
12269
if (persistentConditions)
12270
{
12271
generateDepLabelInstruction(cg, TR::InstOpCode::b, node, labelPersistentFailure, persistentConditions);
12272
}
12273
else
12274
{
12275
generateLabelInstruction(cg, TR::InstOpCode::b, node, labelPersistentFailure);
12276
}
12277
}
12278
else
12279
{
12280
generateInstruction(cg, TR::InstOpCode::tbegin_r, node);
12281
}
12282
12283
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node,
12284
lockwordLabel, cndReg);
12285
12286
generateTrg1Instruction(cg, TR::InstOpCode::mftexasru, node, monReg);
12287
12288
// This mask *should* correspond to the TEXASR failure persistent bit (8)
12289
// NOT the abort bit (31, indicates an explicit abort)
12290
//loadConstant(cg, node, 0x01000001, tempReg);
12291
loadConstant(cg, node, 0x01000000, tempReg);
12292
generateTrg1Src2Instruction(cg, TR::InstOpCode::and_r, node, tempReg, tempReg, monReg);
12293
if (transientConditions)
12294
{
12295
generateDepConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, labelTransientFailure, cndReg, transientConditions);
12296
}
12297
else
12298
{
12299
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, labelTransientFailure, cndReg);
12300
}
12301
if (persistentConditions)
12302
{
12303
generateDepLabelInstruction(cg, TR::InstOpCode::b, node, labelPersistentFailure, persistentConditions);
12304
}
12305
else
12306
{
12307
generateLabelInstruction(cg, TR::InstOpCode::b, node, labelPersistentFailure);
12308
}
12309
12310
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, lockwordLabel, conditions);
12311
12312
int32_t lwOffset = cg->fej9()->getByteOffsetToLockword((TR_OpaqueClassBlock *) cg->getMonClass(node));
12313
12314
if (comp->target().is64Bit() && cg->fej9()->generateCompressedLockWord())
12315
{
12316
generateTrg1MemInstruction(cg, TR::InstOpCode::lwz, node, monReg,
12317
TR::MemoryReference::createWithDisplacement(cg, objReg, lwOffset, 4));
12318
}
12319
else
12320
{
12321
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, monReg,
12322
TR::MemoryReference::createWithDisplacement(cg, objReg, lwOffset, TR::Compiler->om.sizeofReferenceAddress()));
12323
}
12324
12325
// abort if lock is held
12326
if (comp->target().is32Bit() || cg->fej9()->generateCompressedLockWord())
12327
{
12328
generateSrc1Instruction(cg, TR::InstOpCode::tabortwneqi_r, node, monReg, 0);
12329
}
12330
else
12331
{
12332
generateSrc1Instruction(cg, TR::InstOpCode::tabortdneqi_r, node, monReg, 0);
12333
}
12334
12335
TR::TreeTop *BBendTreeTop = cg->getCurrentEvaluationTreeTop()->getNextTreeTop();
12336
TR::TreeTop *BBstartTreeTop = NULL;
12337
if (BBendTreeTop)
12338
BBstartTreeTop = BBendTreeTop->getNextTreeTop();
12339
TR::TreeTop *fallThruTarget = fallThrough->getBranchDestination();
12340
12341
if (BBstartTreeTop && (fallThruTarget == BBstartTreeTop))
12342
{
12343
if (fallThroughConditions)
12344
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, startLabel, fallThroughConditions);
12345
else
12346
generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);
12347
}
12348
else
12349
{
12350
if (fallThroughConditions)
12351
generateDepLabelInstruction(cg, TR::InstOpCode::b, node, labelfallThrough, fallThroughConditions);
12352
else
12353
generateLabelInstruction(cg, TR::InstOpCode::b, node, labelfallThrough);
12354
}
12355
12356
cg->stopUsingRegister(monReg);
12357
cg->stopUsingRegister(cndReg);
12358
cg->stopUsingRegister(tempReg);
12359
12360
cg->decReferenceCount(objNode);
12361
cg->decReferenceCount(persistentFailureNode);
12362
cg->decReferenceCount(transientFailureNode);
12363
cg->decReferenceCount(fallThrough);
12364
12365
return NULL;
12366
}
12367
12368
TR::Register *J9::Power::TreeEvaluator::tfinishEvaluator(TR::Node *node, TR::CodeGenerator *cg)
12369
{
12370
generateInstruction(cg, TR::InstOpCode::tend_r, node);
12371
return NULL;
12372
}
12373
12374
TR::Register *J9::Power::TreeEvaluator::tabortEvaluator(TR::Node *node, TR::CodeGenerator *cg)
12375
{
12376
generateInstruction(cg, TR::InstOpCode::tabort_r, node);
12377
return NULL;
12378
}
12379
12380
TR::Register *J9::Power::TreeEvaluator::arraycopyEvaluator(TR::Node *node, TR::CodeGenerator *cg)
12381
{
12382
#ifdef OMR_GC_CONCURRENT_SCAVENGER
12383
/*
12384
* This version of arraycopyEvaluator is designed to handle the special case where read barriers are
12385
* needed for field loads. At the time of writing, read barriers are used for Concurrent Scavenge GC.
12386
* If there are no read barriers then the original implementation of arraycopyEvaluator can be used.
12387
*/
12388
if (TR::Compiler->om.readBarrierType() == gc_modron_readbar_none ||
12389
!node->chkNoArrayStoreCheckArrayCopy() ||
12390
!node->isReferenceArrayCopy() ||
12391
debug("noArrayCopy")
12392
)
12393
{
12394
return OMR::TreeEvaluatorConnector::arraycopyEvaluator(node, cg);
12395
}
12396
12397
TR::Compilation *comp = cg->comp();
12398
TR::Instruction *gcPoint;
12399
TR::Node *srcObjNode, *dstObjNode, *srcAddrNode, *dstAddrNode, *lengthNode;
12400
TR::Register *srcObjReg, *dstObjReg, *srcAddrReg, *dstAddrReg, *lengthReg;
12401
bool stopUsingCopyReg1, stopUsingCopyReg2, stopUsingCopyReg3, stopUsingCopyReg4, stopUsingCopyReg5 = false;
12402
12403
srcObjNode = node->getChild(0);
12404
dstObjNode = node->getChild(1);
12405
srcAddrNode = node->getChild(2);
12406
dstAddrNode = node->getChild(3);
12407
lengthNode = node->getChild(4);
12408
12409
// These calls evaluate the nodes and give back registers that can be clobbered if needed.
12410
stopUsingCopyReg1 = TR::TreeEvaluator::stopUsingCopyReg(srcObjNode, srcObjReg, cg);
12411
stopUsingCopyReg2 = TR::TreeEvaluator::stopUsingCopyReg(dstObjNode, dstObjReg, cg);
12412
stopUsingCopyReg3 = TR::TreeEvaluator::stopUsingCopyReg(srcAddrNode, srcAddrReg, cg);
12413
stopUsingCopyReg4 = TR::TreeEvaluator::stopUsingCopyReg(dstAddrNode, dstAddrReg, cg);
12414
12415
lengthReg = cg->evaluate(lengthNode);
12416
if (!cg->canClobberNodesRegister(lengthNode))
12417
{
12418
TR::Register *lenCopyReg = cg->allocateRegister();
12419
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, lengthNode, lenCopyReg, lengthReg);
12420
lengthReg = lenCopyReg;
12421
stopUsingCopyReg5 = true;
12422
}
12423
12424
// Inline forward arrayCopy with constant length.
12425
int64_t len = -1;
12426
if (node->isForwardArrayCopy() && lengthNode->getOpCode().isLoadConst())
12427
{
12428
len = (lengthNode->getType().isInt32() ? lengthNode->getInt() : lengthNode->getLongInt());
12429
12430
// inlineArrayCopy_ICF is not currently capable of handling very long lengths correctly. Under some circumstances,
12431
// it will generate an li instruction with an out-of-bounds immediate, which triggers an assert in the binary
12432
// encoder.
12433
if (len >= 0 && len < MAX_PPC_ARRAYCOPY_INLINE)
12434
{
12435
/*
12436
* This path generates code to perform a runtime check on whether concurrent GC is done moving objects or not.
12437
* If it isn't, a call to referenceArrayCopy helper should be made.
12438
* If it is, using the inlined array copy code path is okay.
12439
*/
12440
int32_t groups;
12441
12442
// Our hands are tied somewhat due to the potential ReferenceArrayCopy call
12443
// We can really work with less registers in P10 case. For readability and
12444
// maintainability, we are simplifying the logic but using more registers.
12445
12446
bool postP10CopyInline = cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10) &&
12447
cg->comp()->target().cpu.supportsFeature(OMR_FEATURE_PPC_HAS_VSX);
12448
12449
static bool disableLEArrayCopyInline = (feGetEnv("TR_disableLEArrayCopyInline") != NULL);
12450
bool supportsLEArrayCopyInline = cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P8) &&
12451
!disableLEArrayCopyInline &&
12452
comp->target().cpu.isLittleEndian() &&
12453
comp->target().cpu.hasFPU() &&
12454
comp->target().is64Bit();
12455
12456
// There are a minimum of 9 dependencies.
12457
uint8_t numDeps = 9;
12458
12459
if (comp->target().is64Bit())
12460
{
12461
groups = len >> 5;
12462
}
12463
else
12464
{
12465
groups = len >> 4;
12466
}
12467
12468
TR::Register *condReg = cg->allocateRegister(TR_CCR);
12469
12470
// These registers are used when taking the inlineArrayCopy_ICF path.
12471
TR::Register *tmp1Reg = cg->allocateRegister(TR_GPR);
12472
TR::Register *tmp2Reg = NULL;
12473
TR::Register *tmp3Reg = NULL;
12474
TR::Register *tmp4Reg = NULL;
12475
TR::Register *fp1Reg = NULL;
12476
TR::Register *fp2Reg = NULL;
12477
TR::Register *fp3Reg = NULL;
12478
TR::Register *fp4Reg = NULL;
12479
12480
// These registers are used when taking the referenceArrayCopy helper call path.
12481
TR::Register *r3Reg = cg->allocateRegister();
12482
TR::Register *metaReg = cg->getMethodMetaDataRegister();
12483
12484
if (postP10CopyInline)
12485
{
12486
numDeps += 1;
12487
fp1Reg = cg->allocateRegister(TR_VSX_VECTOR);
12488
}
12489
else
12490
{
12491
if (groups != 0)
12492
{
12493
numDeps += 3;
12494
tmp2Reg = cg->allocateRegister(TR_GPR);
12495
tmp3Reg = cg->allocateRegister(TR_GPR);
12496
tmp4Reg = cg->allocateRegister(TR_GPR);
12497
}
12498
12499
if (supportsLEArrayCopyInline)
12500
{
12501
numDeps += 4;
12502
fp1Reg = cg->allocateRegister(TR_FPR);
12503
fp2Reg = cg->allocateRegister(TR_FPR);
12504
fp3Reg = cg->allocateRegister(TR_FPR);
12505
fp4Reg = cg->allocateRegister(TR_FPR);
12506
}
12507
}
12508
12509
/*
12510
* r3-r8 are used to pass parameters to the referenceArrayCopy helper.
12511
* r11 is used for the tmp1Reg since r11 gets killed by the trampoline and values put into tmp1Reg are not needed after the trampoline.
12512
*/
12513
TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, numDeps, cg->trMemory());
12514
deps->addPostCondition(condReg, TR::RealRegister::cr0);
12515
deps->addPostCondition(metaReg, TR::RealRegister::NoReg);
12516
12517
deps->addPostCondition(r3Reg, TR::RealRegister::gr3);
12518
deps->addPostCondition(srcObjReg, TR::RealRegister::gr4);
12519
deps->addPostCondition(dstObjReg, TR::RealRegister::gr5);
12520
deps->addPostCondition(srcAddrReg, TR::RealRegister::gr6);
12521
deps->addPostCondition(dstAddrReg, TR::RealRegister::gr7);
12522
deps->addPostCondition(lengthReg, TR::RealRegister::gr8);
12523
12524
deps->addPostCondition( tmp1Reg, TR::RealRegister::gr11);
12525
12526
if (postP10CopyInline)
12527
{
12528
deps->addPostCondition(fp1Reg, TR::RealRegister::NoReg);
12529
}
12530
else
12531
{
12532
if (groups != 0)
12533
{
12534
deps->addPostCondition(tmp2Reg, TR::RealRegister::NoReg);
12535
deps->addPostCondition(tmp3Reg, TR::RealRegister::NoReg);
12536
deps->addPostCondition(tmp4Reg, TR::RealRegister::NoReg);
12537
}
12538
12539
if (supportsLEArrayCopyInline)
12540
{
12541
deps->addPostCondition(fp1Reg, TR::RealRegister::NoReg);
12542
deps->addPostCondition(fp2Reg, TR::RealRegister::NoReg);
12543
deps->addPostCondition(fp3Reg, TR::RealRegister::NoReg);
12544
deps->addPostCondition(fp4Reg, TR::RealRegister::NoReg);
12545
}
12546
}
12547
12548
TR::LabelSymbol *startLabel = generateLabelSymbol(cg);
12549
TR::LabelSymbol *helperLabel = generateLabelSymbol(cg);
12550
TR::LabelSymbol *endLabel = generateLabelSymbol(cg);
12551
startLabel->setStartInternalControlFlow();
12552
endLabel->setEndInternalControlFlow();
12553
12554
generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);
12555
12556
// Runtime check for concurrent scavenger.
12557
generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, tmp1Reg,
12558
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, readBarrierRangeCheckTop), TR::Compiler->om.sizeofReferenceAddress()));
12559
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::Op_cmpli, node, condReg, tmp1Reg, 0);
12560
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, helperLabel, condReg);
12561
12562
// Generate assembly for inlined version of array copy.
12563
inlineArrayCopy_ICF(node, len, srcAddrReg, dstAddrReg, cg, condReg,
12564
tmp1Reg, tmp2Reg, tmp3Reg, tmp4Reg,
12565
fp1Reg, fp2Reg, fp3Reg, fp4Reg);
12566
12567
generateLabelInstruction(cg, TR::InstOpCode::b, node, endLabel);
12568
12569
// Start of referenceArrayCopy helper path.
12570
generateLabelInstruction(cg, TR::InstOpCode::label, node, helperLabel);
12571
12572
J9::Power::JNILinkage *jniLinkage = (J9::Power::JNILinkage*) cg->getLinkage(TR_J9JNILinkage);
12573
const TR::PPCLinkageProperties &pp = jniLinkage->getProperties();
12574
12575
int32_t elementSize;
12576
if (comp->useCompressedPointers())
12577
elementSize = TR::Compiler->om.sizeofReferenceField();
12578
else
12579
elementSize = (int32_t) TR::Compiler->om.sizeofReferenceAddress();
12580
12581
// Sign extend non-64bit Integers on LinuxPPC64 as required by the ABI
12582
if (comp->target().isLinux() && comp->target().is64Bit())
12583
{
12584
generateTrg1Src1Instruction(cg, TR::InstOpCode::extsw, node, lengthReg, lengthReg);
12585
}
12586
12587
// The C routine expects length measured by slots.
12588
generateShiftRightLogicalImmediate(cg, node, lengthReg, lengthReg, trailingZeroes(elementSize));
12589
12590
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, r3Reg, metaReg);
12591
12592
TR::RegisterDependencyConditions *helperDeps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 0, cg->trMemory());
12593
TR::SymbolReference *helperSym = comp->getSymRefTab()->findOrCreateRuntimeHelper(TR_referenceArrayCopy);
12594
12595
gcPoint = generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)helperSym->getMethodAddress(), helperDeps, helperSym);
12596
gcPoint->PPCNeedsGCMap(pp.getPreservedRegisterMapForGC());
12597
12598
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, endLabel, deps);
12599
12600
TR::TreeEvaluator::genWrtbarForArrayCopy(node, srcObjReg, dstObjReg, cg);
12601
12602
TR::Register *retRegisters[5];
12603
int retRegCount = 0;
12604
cg->decReferenceCount(srcObjNode);
12605
cg->decReferenceCount(dstObjNode);
12606
cg->decReferenceCount(srcAddrNode);
12607
cg->decReferenceCount(dstAddrNode);
12608
cg->decReferenceCount(lengthNode);
12609
12610
// Don't kill the registers that should not be clobbered
12611
if (!stopUsingCopyReg1)
12612
retRegisters[retRegCount++] = srcObjReg;
12613
if (!stopUsingCopyReg2)
12614
retRegisters[retRegCount++] = dstObjReg;
12615
if (!stopUsingCopyReg3)
12616
retRegisters[retRegCount++] = srcAddrReg;
12617
if (!stopUsingCopyReg4)
12618
retRegisters[retRegCount++] = dstAddrReg;
12619
if (!stopUsingCopyReg5)
12620
retRegisters[retRegCount++] = lengthReg;
12621
12622
deps->stopUsingDepRegs(cg, retRegCount, retRegisters);
12623
cg->machine()->setLinkRegisterKilled(true);
12624
cg->setHasCall();
12625
12626
return NULL;
12627
}
12628
}
12629
12630
/*
12631
* This path also generates code to perform a runtime check on whether concurrent GC is done moving objects or not.
12632
* If it isn't done, once again a call to referenceArrayCopy helper should be made.
12633
* If it is done, using the assembly helpers code path is okay.
12634
*/
12635
12636
TR::Register *condReg = cg->allocateRegister(TR_CCR);
12637
12638
// These registers are used when taking the assembly helpers path
12639
TR::Register *tmp1Reg = cg->allocateRegister(TR_GPR);
12640
TR::Register *tmp2Reg = cg->allocateRegister(TR_GPR);
12641
TR::Register *tmp3Reg = cg->allocateRegister(TR_GPR);
12642
TR::Register *tmp4Reg = cg->allocateRegister(TR_GPR);
12643
TR::Register *fp1Reg = NULL;
12644
TR::Register *fp2Reg = NULL;
12645
TR::Register *vec0Reg = NULL;
12646
TR::Register *vec1Reg = NULL;
12647
12648
// These registers are used when taking the referenceArrayCopy helper call path.
12649
TR::Register *r3Reg = cg->allocateRegister();
12650
TR::Register *r4Reg = cg->allocateRegister();
12651
TR::Register *metaReg = cg->getMethodMetaDataRegister();
12652
12653
// This section calculates the number of dependencies needed by the assembly helpers path.
12654
bool postP10Copy = cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P10) &&
12655
cg->comp()->target().cpu.supportsFeature(OMR_FEATURE_PPC_HAS_VSX);
12656
12657
static bool disableVSXArrayCopy = (feGetEnv("TR_disableVSXArrayCopy") != NULL);
12658
bool useVSXForCopy = cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P8) &&
12659
!disableVSXArrayCopy && cg->comp()->target().cpu.supportsFeature(OMR_FEATURE_PPC_HAS_VSX);
12660
12661
// VSX supercedes FPU. No reason to offering disable option on this.
12662
// POWER8 potentially micro-coded unaligned integer accesses in LE mode,
12663
// breaking the guarantee of data atomicity. So, we use floating point
12664
// accesses instead.
12665
bool extraLERequirement = cg->comp()->target().cpu.isLittleEndian();
12666
12667
#if defined(DEBUG) || defined(PROD_WITH_ASSUMES)
12668
static bool verboseArrayCopy = (feGetEnv("TR_verboseArrayCopy") != NULL); //Check which helper is getting used.
12669
if (verboseArrayCopy)
12670
fprintf(stderr, "arraycopy [0x%p] isReferenceArrayCopy:[%d] isForwardArrayCopy:[%d] isHalfWordElementArrayCopy:[%d] isWordElementArrayCopy:[%d] %s @ %s\n",
12671
node,
12672
0,
12673
node->isForwardArrayCopy(),
12674
node->isHalfWordElementArrayCopy(),
12675
node->isWordElementArrayCopy(),
12676
comp->signature(),
12677
comp->getHotnessName(comp->getMethodHotness())
12678
);
12679
#endif
12680
12681
/*
12682
* The minimum number of dependencies used by the assembly helpers path is 8.
12683
* The number of dependencies added by the referenceArrayCopy helper call path is 5.
12684
*/
12685
int32_t numDeps = 8 + 5;
12686
12687
if (postP10Copy)
12688
{
12689
// Due to the potential ReferenceArrayCopy call, our hands are tied somewhat.
12690
// Strictly for arrayCopy call, we don't need that many registers at all.
12691
12692
numDeps += 4;
12693
}
12694
else if (useVSXForCopy)
12695
{
12696
vec0Reg = cg->allocateRegister(TR_VRF);
12697
vec1Reg = cg->allocateRegister(TR_VRF);
12698
numDeps += 2;
12699
if (comp->target().is32Bit())
12700
{
12701
numDeps += 1;
12702
}
12703
if (extraLERequirement)
12704
{
12705
fp1Reg = cg->allocateSinglePrecisionRegister();
12706
fp2Reg = cg->allocateSinglePrecisionRegister();
12707
numDeps += 4;
12708
}
12709
}
12710
else if (comp->target().is32Bit())
12711
{
12712
numDeps += 1;
12713
if (comp->target().cpu.hasFPU())
12714
{
12715
numDeps += 4;
12716
}
12717
}
12718
else if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P6))
12719
{
12720
numDeps += 4;
12721
}
12722
12723
TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(numDeps, numDeps, cg->trMemory());
12724
12725
/*
12726
* Build up the dependency conditions for assembly helper path.
12727
* Unfortunately, the two different paths have a conflict regarding which real register they want srcAddrReg, dstAddrReg and lengthReg in.
12728
* Dependencies are set up to favour the fast assembly path. Register moves are used in the slow helper path to move the values to the
12729
* real registers they are expected to be in.
12730
*/
12731
TR::addDependency(deps, condReg, TR::RealRegister::cr0, TR_CCR, cg);
12732
12733
TR::addDependency(deps, lengthReg, TR::RealRegister::gr7, TR_GPR, cg);
12734
TR::addDependency(deps, srcAddrReg, TR::RealRegister::gr8, TR_GPR, cg);
12735
TR::addDependency(deps, dstAddrReg, TR::RealRegister::gr9, TR_GPR, cg);
12736
12737
TR::addDependency(deps, tmp1Reg, TR::RealRegister::gr5, TR_GPR, cg);
12738
TR::addDependency(deps, tmp2Reg, TR::RealRegister::gr6, TR_GPR, cg);
12739
TR::addDependency(deps, tmp3Reg, TR::RealRegister::gr0, TR_GPR, cg);
12740
TR::addDependency(deps, tmp4Reg, TR::RealRegister::gr11, TR_GPR, cg); // Trampoline kills gr11.
12741
12742
if (postP10Copy)
12743
{
12744
TR::addDependency(deps, NULL, TR::RealRegister::vsr8, TR_VSX_VECTOR, cg);
12745
TR::addDependency(deps, NULL, TR::RealRegister::vsr9, TR_VSX_VECTOR, cg);
12746
TR::addDependency(deps, NULL, TR::RealRegister::vsr32, TR_VSX_VECTOR, cg);
12747
TR::addDependency(deps, NULL, TR::RealRegister::vsr33, TR_VSX_VECTOR, cg);
12748
}
12749
else if (useVSXForCopy)
12750
{
12751
TR::addDependency(deps, vec0Reg, TR::RealRegister::vr0, TR_VRF, cg);
12752
TR::addDependency(deps, vec1Reg, TR::RealRegister::vr1, TR_VRF, cg);
12753
if (comp->target().is32Bit())
12754
{
12755
TR::addDependency(deps, NULL, TR::RealRegister::gr10, TR_GPR, cg);
12756
}
12757
if (extraLERequirement)
12758
{
12759
TR::addDependency(deps, fp1Reg, TR::RealRegister::fp8, TR_FPR, cg);
12760
TR::addDependency(deps, fp2Reg, TR::RealRegister::fp9, TR_FPR, cg);
12761
TR::addDependency(deps, NULL, TR::RealRegister::fp10, TR_FPR, cg);
12762
TR::addDependency(deps, NULL, TR::RealRegister::fp11, TR_FPR, cg);
12763
}
12764
}
12765
else if (comp->target().is32Bit())
12766
{
12767
TR::addDependency(deps, NULL, TR::RealRegister::gr10, TR_GPR, cg);
12768
if (comp->target().cpu.hasFPU())
12769
{
12770
TR::addDependency(deps, NULL, TR::RealRegister::fp8, TR_FPR, cg);
12771
TR::addDependency(deps, NULL, TR::RealRegister::fp9, TR_FPR, cg);
12772
TR::addDependency(deps, NULL, TR::RealRegister::fp10, TR_FPR, cg);
12773
TR::addDependency(deps, NULL, TR::RealRegister::fp11, TR_FPR, cg);
12774
}
12775
}
12776
else if (comp->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P6))
12777
{
12778
// stfdp arrayCopy used
12779
TR::addDependency(deps, NULL, TR::RealRegister::fp8, TR_FPR, cg);
12780
TR::addDependency(deps, NULL, TR::RealRegister::fp9, TR_FPR, cg);
12781
TR::addDependency(deps, NULL, TR::RealRegister::fp10, TR_FPR, cg);
12782
TR::addDependency(deps, NULL, TR::RealRegister::fp11, TR_FPR, cg);
12783
}
12784
12785
// Add dependencies for the referenceArrayCopy helper call path.
12786
TR::addDependency(deps, r3Reg, TR::RealRegister::gr3, TR_GPR, cg);
12787
TR::addDependency(deps, r4Reg, TR::RealRegister::gr4, TR_GPR, cg);
12788
12789
TR::addDependency(deps, srcObjReg, TR::RealRegister::NoReg, TR_GPR, cg);
12790
TR::addDependency(deps, dstObjReg, TR::RealRegister::NoReg, TR_GPR, cg);
12791
TR::addDependency(deps, metaReg, TR::RealRegister::NoReg, TR_GPR, cg);
12792
12793
TR::LabelSymbol *startLabel = generateLabelSymbol(cg);
12794
TR::LabelSymbol *helperLabel = generateLabelSymbol(cg);
12795
TR::LabelSymbol *endLabel = generateLabelSymbol(cg);
12796
startLabel->setStartInternalControlFlow();
12797
endLabel->setEndInternalControlFlow();
12798
12799
generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);
12800
12801
// Runtime check for concurrent scavenger.
12802
generateTrg1MemInstruction(cg, TR::InstOpCode::Op_load, node, tmp1Reg,
12803
TR::MemoryReference::createWithDisplacement(cg, metaReg, offsetof(J9VMThread, readBarrierRangeCheckTop), TR::Compiler->om.sizeofReferenceAddress()));
12804
generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::Op_cmpli, node, condReg, tmp1Reg, 0);
12805
generateConditionalBranchInstruction(cg, TR::InstOpCode::bne, node, helperLabel, condReg);
12806
12807
// Start of assembly helper path.
12808
TR_RuntimeHelper helper;
12809
12810
if (node->isForwardArrayCopy())
12811
{
12812
if (postP10Copy)
12813
{
12814
helper = TR_PPCpostP10ForwardCopy;
12815
}
12816
else if (useVSXForCopy)
12817
{
12818
helper = TR_PPCforwardQuadWordArrayCopy_vsx;
12819
}
12820
else if (node->isWordElementArrayCopy())
12821
{
12822
if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P6))
12823
helper = TR_PPCforwardWordArrayCopy_dp;
12824
else
12825
helper = TR_PPCforwardWordArrayCopy;
12826
}
12827
else if (node->isHalfWordElementArrayCopy())
12828
{
12829
if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P6))
12830
helper = TR_PPCforwardHalfWordArrayCopy_dp;
12831
else
12832
helper = TR_PPCforwardHalfWordArrayCopy;
12833
}
12834
else
12835
{
12836
if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P6))
12837
helper = TR_PPCforwardArrayCopy_dp;
12838
else
12839
helper = TR_PPCforwardArrayCopy;
12840
}
12841
}
12842
else // We are not sure it is forward or we have to do backward.
12843
{
12844
if (postP10Copy)
12845
{
12846
helper = TR_PPCpostP10GenericCopy;
12847
}
12848
else if (useVSXForCopy)
12849
{
12850
helper = TR_PPCquadWordArrayCopy_vsx;
12851
}
12852
else if (node->isWordElementArrayCopy())
12853
{
12854
if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P6))
12855
helper = TR_PPCwordArrayCopy_dp;
12856
else
12857
helper = TR_PPCwordArrayCopy;
12858
}
12859
else if (node->isHalfWordElementArrayCopy())
12860
{
12861
if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P6))
12862
helper = TR_PPChalfWordArrayCopy_dp;
12863
else
12864
helper = TR_PPChalfWordArrayCopy;
12865
}
12866
else
12867
{
12868
if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P6))
12869
helper = TR_PPCarrayCopy_dp;
12870
else
12871
helper = TR_PPCarrayCopy;
12872
}
12873
}
12874
TR::TreeEvaluator::generateHelperBranchAndLinkInstruction(helper, node, deps, cg);
12875
12876
generateLabelInstruction(cg, TR::InstOpCode::b, node, endLabel);
12877
12878
// Start of referenceArrayCopy helper path.
12879
generateLabelInstruction(cg, TR::InstOpCode::label, node, helperLabel);
12880
12881
J9::Power::JNILinkage *jniLinkage = (J9::Power::JNILinkage*) cg->getLinkage(TR_J9JNILinkage);
12882
const TR::PPCLinkageProperties &pp = jniLinkage->getProperties();
12883
12884
int32_t elementSize;
12885
if (comp->useCompressedPointers())
12886
elementSize = TR::Compiler->om.sizeofReferenceField();
12887
else
12888
elementSize = (int32_t) TR::Compiler->om.sizeofReferenceAddress();
12889
12890
// Sign extend non-64bit Integers on LinuxPPC64 as required by the ABI
12891
if (comp->target().isLinux() && comp->target().is64Bit())
12892
{
12893
generateTrg1Src1Instruction(cg, TR::InstOpCode::extsw, node, lengthReg, lengthReg);
12894
}
12895
12896
// The C routine expects length measured by slots.
12897
generateShiftRightLogicalImmediate(cg, node, lengthReg, lengthReg, trailingZeroes(elementSize));
12898
12899
/*
12900
* Parameters are set up here
12901
* r3 = vmThread
12902
* r4 = srcObj
12903
* r5 = dstObj
12904
* r6 = srcAddr
12905
* r7 = dstAddr
12906
* r8 = length
12907
*
12908
* CAUTION: Virtual register names are based on their use during the non-helper path so they are misleading after this point.
12909
* Due to register reuse, pay attention to copying order so that a register is not clobbered too early.
12910
*/
12911
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, r3Reg, metaReg);
12912
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, r4Reg, srcObjReg);
12913
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, tmp1Reg, dstObjReg); //tmp1Reg is tied to r5.
12914
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, tmp2Reg, srcAddrReg); //tmp2Reg is tied to r6.
12915
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, srcAddrReg, lengthReg); //srcAddrReg is tied to r8. Need to copy srcAddrReg first.
12916
generateTrg1Src1Instruction(cg, TR::InstOpCode::mr, node, lengthReg, dstAddrReg); //lengthReg is tied to r7. Need to copy lengthReg first.
12917
12918
TR::RegisterDependencyConditions *helperDeps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 0, cg->trMemory());
12919
TR::SymbolReference *helperSym = comp->getSymRefTab()->findOrCreateRuntimeHelper(TR_referenceArrayCopy);
12920
12921
gcPoint = generateDepImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)helperSym->getMethodAddress(), helperDeps, helperSym);
12922
gcPoint->PPCNeedsGCMap(pp.getPreservedRegisterMapForGC());
12923
12924
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, endLabel, deps);
12925
12926
TR::TreeEvaluator::genWrtbarForArrayCopy(node, srcObjReg, dstObjReg, cg);
12927
12928
cg->decReferenceCount(srcObjNode);
12929
cg->decReferenceCount(dstObjNode);
12930
cg->decReferenceCount(srcAddrNode);
12931
cg->decReferenceCount(dstAddrNode);
12932
cg->decReferenceCount(lengthNode);
12933
12934
TR::Register *retRegisters[5];
12935
int retRegCount = 0;
12936
12937
// Don't kill the registers that should not be clobbered
12938
if (!stopUsingCopyReg1)
12939
retRegisters[retRegCount++] = srcObjReg;
12940
if (!stopUsingCopyReg2)
12941
retRegisters[retRegCount++] = dstObjReg;
12942
if (!stopUsingCopyReg3)
12943
retRegisters[retRegCount++] = srcAddrReg;
12944
if (!stopUsingCopyReg4)
12945
retRegisters[retRegCount++] = dstAddrReg;
12946
if (!stopUsingCopyReg5)
12947
retRegisters[retRegCount++] = lengthReg;
12948
12949
deps->stopUsingDepRegs(cg, retRegCount, retRegisters);
12950
cg->machine()->setLinkRegisterKilled(true);
12951
cg->setHasCall();
12952
12953
return NULL;
12954
#else /* OMR_GC_CONCURRENT_SCAVENGER */
12955
return OMR::TreeEvaluatorConnector::arraycopyEvaluator(node, cg);
12956
#endif /* OMR_GC_CONCURRENT_SCAVENGER */
12957
}
12958
12959
TR::Register *
12960
J9::Power::TreeEvaluator::NULLCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)
12961
{
12962
return TR::TreeEvaluator::evaluateNULLCHKWithPossibleResolve(node, false, cg);
12963
}
12964
12965
TR::Register *
12966
J9::Power::TreeEvaluator::resolveAndNULLCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)
12967
{
12968
return TR::TreeEvaluator::evaluateNULLCHKWithPossibleResolve(node, true, cg);
12969
}
12970
12971
TR::Register *
12972
J9::Power::TreeEvaluator::evaluateNULLCHKWithPossibleResolve(TR::Node *node, bool needsResolve, TR::CodeGenerator *cg)
12973
{
12974
// NOTE:
12975
// If in the future no code is generated for the null check, just evaluate the
12976
// child and decrement its use count UNLESS the child is a pass-through node
12977
// in which case some kind of explicit test or indirect load must be generated
12978
// to force the null check at this point.
12979
12980
TR::Node *firstChild = node->getFirstChild();
12981
TR::ILOpCode &opCode = firstChild->getOpCode();
12982
TR::Node *reference = NULL;
12983
TR::Compilation *comp = cg->comp();
12984
12985
bool hasCompressedPointers = false;
12986
if (comp->useCompressedPointers()
12987
&& firstChild->getOpCodeValue() == TR::l2a)
12988
{
12989
hasCompressedPointers = true;
12990
TR::ILOpCodes loadOp = comp->il.opCodeForIndirectLoad(TR::Int32);
12991
TR::ILOpCodes rdbarOp = comp->il.opCodeForIndirectReadBarrier(TR::Int32);
12992
TR::Node *n = firstChild;
12993
while ((n->getOpCodeValue() != loadOp) && (n->getOpCodeValue() != rdbarOp))
12994
n = n->getFirstChild();
12995
reference = n->getFirstChild();
12996
}
12997
else
12998
reference = node->getNullCheckReference();
12999
13000
// TODO - If a resolve check is needed as well, the resolve must be done
13001
// before the null check, so that exceptions are handled in the correct
13002
// order.
13003
//
13004
///// if (needsResolve)
13005
///// {
13006
///// ...
13007
///// }
13008
13009
TR::Register *trgReg = cg->evaluate(reference);
13010
TR::Instruction *gcPoint;
13011
13012
gcPoint = TR::TreeEvaluator::generateNullTestInstructions(cg, trgReg, node);
13013
13014
gcPoint->PPCNeedsGCMap(0xFFFFFFFF);
13015
13016
TR::Node *n = NULL;
13017
if (comp->useCompressedPointers()
13018
&& reference->getOpCodeValue() == TR::l2a)
13019
{
13020
reference->setIsNonNull(true);
13021
n = reference->getFirstChild();
13022
TR::ILOpCodes loadOp = comp->il.opCodeForIndirectLoad(TR::Int32);
13023
TR::ILOpCodes rdbarOp = comp->il.opCodeForIndirectReadBarrier(TR::Int32);
13024
while ((n->getOpCodeValue() != loadOp) && (n->getOpCodeValue() != rdbarOp))
13025
{
13026
n->setIsNonZero(true);
13027
n = n->getFirstChild();
13028
}
13029
n->setIsNonZero(true);
13030
}
13031
13032
reference->setIsNonNull(true);
13033
13034
cg->evaluate(firstChild);
13035
cg->decReferenceCount(firstChild);
13036
13037
return NULL;
13038
}
13039
13040