Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/arm/codegen/J9TreeEvaluator.cpp
6004 views
1
/*******************************************************************************
2
* Copyright (c) 2000, 2021 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21
*******************************************************************************/
22
23
#include "j9.h"
24
#include "j9cfg.h"
25
#include "j9consts.h"
26
#include "omrmodroncore.h"
27
#include "thrdsup.h"
28
#include "thrtypes.h"
29
#include "codegen/CodeGenerator.hpp"
30
#include "codegen/CodeGeneratorUtils.hpp"
31
#include "codegen/Machine.hpp"
32
#include "codegen/Linkage.hpp"
33
#include "codegen/Linkage_inlines.hpp"
34
#include "codegen/TreeEvaluator.hpp"
35
#include "env/jittypes.h"
36
#include "il/DataTypes.hpp"
37
#include "il/LabelSymbol.hpp"
38
#include "il/Node.hpp"
39
#include "il/Node_inlines.hpp"
40
#include "arm/codegen/ARMInstruction.hpp"
41
#include "arm/codegen/GenerateInstructions.hpp"
42
43
/*
44
* J9 ARM specific tree evaluator table overrides
45
*/
46
extern void TEMPORARY_initJ9ARMTreeEvaluatorTable(TR::CodeGenerator *cg)
47
{
48
TR_TreeEvaluatorFunctionPointer *tet = cg->getTreeEvaluatorTable();
49
50
tet[TR::ResolveCHK] = TR::TreeEvaluator::resolveCHKEvaluator;
51
tet[TR::monexitfence] = TR::TreeEvaluator::monexitfenceEvaluator;
52
tet[TR::NULLCHK] = TR::TreeEvaluator::NULLCHKEvaluator;
53
tet[TR::ResolveAndNULLCHK] = TR::TreeEvaluator::resolveAndNULLCHKEvaluator;
54
}
55
56
TR::Register *
57
J9::ARM::TreeEvaluator::NULLCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)
58
{
59
return TR::TreeEvaluator::evaluateNULLCHKWithPossibleResolve(node, false, cg);
60
}
61
62
TR::Register *
63
J9::ARM::TreeEvaluator::resolveAndNULLCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)
64
{
65
return TR::TreeEvaluator::evaluateNULLCHKWithPossibleResolve(node, true, cg);
66
}
67
68
TR::Register *
69
J9::ARM::TreeEvaluator::evaluateNULLCHKWithPossibleResolve(TR::Node *node, bool needsResolve, TR::CodeGenerator *cg)
70
{
71
// NOTE:
72
// If no code is generated for the null check, just evaluate the
73
// child and decrement its use count UNLESS the child is a pass-through node
74
// in which case some kind of explicit test or indirect load must be generated
75
// to force the null check at this point.
76
77
// Generate the code for the null check
78
//
79
TR::Node *firstChild = node->getFirstChild();
80
TR::ILOpCode &opCode = firstChild->getOpCode();
81
TR::Node *reference = node->getNullCheckReference();
82
83
// Skip the NULLCHK for TR::loadaddr nodes.
84
//
85
if (reference->getOpCodeValue() == TR::loadaddr)
86
{
87
cg->evaluate(firstChild);
88
firstChild->decReferenceCount();
89
return NULL;
90
}
91
92
bool needCode = !(cg->canNullChkBeImplicit(node, true));
93
94
// nullchk is not implicit
95
//
96
if (needCode)
97
{
98
// TODO - If a resolve check is needed as well, the resolve must be done
99
// before the null check, so that exceptions are handled in the correct
100
// order.
101
//
102
///// if (needsResolve)
103
///// {
104
///// ...
105
///// }
106
107
TR::Register *targetRegister = cg->evaluate(reference);
108
109
generateSrc2Instruction(cg, TR::InstOpCode::tst, node, targetRegister, targetRegister);
110
111
TR::SymbolReference *NULLCHKException = node->getSymbolReference();
112
TR::Instruction *instr1 = generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)NULLCHKException->getMethodAddress(), NULL, NULLCHKException, NULL, NULL, ARMConditionCodeEQ);
113
instr1->ARMNeedsGCMap(0xFFFFFFFF);
114
cg->machine()->setLinkRegisterKilled(true);
115
}
116
117
// For a load, if this is the only use decrement the use count on the
118
// grandchild since it has already been evaluated.
119
// Otherwise just evaluate the child.
120
//
121
if (needCode && opCode.isLoad()
122
&& firstChild->getReferenceCount() == 1
123
&& firstChild->getSymbolReference()
124
&& !firstChild->getSymbolReference()->isUnresolved())
125
{
126
firstChild->decReferenceCount();
127
reference->decReferenceCount();
128
}
129
else
130
{
131
cg->evaluate(firstChild);
132
firstChild->decReferenceCount();
133
}
134
135
// If an explicit check has not been generated for the null check, there is
136
// an instruction that will cause a hardware trap if the exception is to be
137
// taken. If this method may catch the exception, a GC stack map must be
138
// created for this instruction. All registers are valid at this GC point
139
// TODO - if the method may not catch the exception we still need to note
140
// that the GC point exists, since maps before this point and after it cannot
141
// be merged.
142
//
143
/////if (!needCode && comp->getMethodSymbol()->isEHAwareMethod())
144
if (!needCode)
145
{
146
TR::Instruction *faultingInstruction = cg->getImplicitExceptionPoint();
147
if (faultingInstruction)
148
faultingInstruction->setNeedsGCMap();
149
}
150
151
reference->setIsNonNull(true);
152
153
return NULL;
154
}
155
156
/**
157
* \brief
158
* Generates code for card marking checks
159
*
160
* \parm dstReg
161
* Register for destination object
162
*
163
* \parm temp1Reg
164
* Temporary register
165
*
166
* \parm temp2Reg
167
* Temporary register
168
*
169
* \parm temp3Reg
170
* Temporary register
171
*
172
* \parm deps
173
* Register dependencies to be satisfied at the end of code
174
*/
175
static void VMCardCheckEvaluator(TR::Node *node, TR::Register *dstReg, TR::Register *temp1Reg, TR::Register *temp2Reg, TR::Register *temp3Reg,
176
TR::RegisterDependencyConditions *deps, TR::CodeGenerator *cg)
177
{
178
TR::Compilation * comp = cg->comp();
179
// non-heap objects cannot be marked
180
// Make sure we really should be here
181
TR::Options *options = comp->getOptions();
182
TR::Node *wrtbarNode = NULL;
183
bool definitelyHeapObject = false, definitelyNonHeapObject = false;
184
auto gcMode = TR::Compiler->om.writeBarrierType();
185
186
if (node->getOpCodeValue() == TR::awrtbari || node->getOpCodeValue() == TR::awrtbar)
187
wrtbarNode = node;
188
else if (node->getOpCodeValue() == TR::ArrayStoreCHK)
189
wrtbarNode = node->getFirstChild();
190
191
if (wrtbarNode != NULL)
192
{
193
definitelyHeapObject = wrtbarNode->isHeapObjectWrtBar();
194
definitelyNonHeapObject = wrtbarNode->isNonHeapObjectWrtBar();
195
}
196
197
TR_ASSERT((gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_cardmark_incremental) && !definitelyNonHeapObject,
198
"VMCardCheckEvaluator: Invalid call to cardCheckEvaluator\n");
199
200
if (!definitelyNonHeapObject)
201
{
202
TR::Register *metaReg = cg->getMethodMetaDataRegister();
203
TR::LabelSymbol *noChkLabel = generateLabelSymbol(cg);
204
205
// Balanced policy must always dirty the card table.
206
//
207
if (gcMode != gc_modron_wrtbar_cardmark_incremental)
208
{
209
uint32_t base, rotate;
210
211
generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, temp1Reg,
212
new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, privateFlags), cg));
213
214
// The value for J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE is a generated value when VM code is created
215
// At the moment we are safe here, but it is better to be careful and avoid any unexpected behaviour
216
// Make sure this falls within the scope of tst
217
//
218
TR_ASSERT(J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE >= 0x00010000 && J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE <= 0x80000000,
219
"Concurrent mark active Value assumption broken.");
220
constantIsImmed8r(J9_PRIVATE_FLAGS_CONCURRENT_MARK_ACTIVE, &base, &rotate);
221
generateSrc1ImmInstruction(cg, TR::InstOpCode::tst, node, temp1Reg, base, rotate);
222
generateConditionalBranchInstruction(cg, node, ARMConditionCodeEQ, noChkLabel);
223
}
224
225
uintptr_t card_size_shift = trailingZeroes((uint32_t) options->getGcCardSize());
226
227
// temp3Reg = dstReg - heapBaseForBarrierRange0
228
generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, temp3Reg,
229
new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, heapBaseForBarrierRange0), cg));
230
generateTrg1Src2Instruction(cg, TR::InstOpCode::sub, node, temp3Reg, dstReg, temp3Reg);
231
232
if (!definitelyHeapObject)
233
{
234
// if (temp3Reg >= heapSizeForBarrierRange0), object not in the heap
235
generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, temp1Reg,
236
new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, heapSizeForBarrierRange0), cg));
237
generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, temp3Reg, temp1Reg);
238
generateConditionalBranchInstruction(cg, node, ARMConditionCodeCS, noChkLabel);
239
}
240
241
// dirty(activeCardTableBase + temp3Reg >> card_size_shift)
242
generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, temp1Reg,
243
new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, activeCardTableBase), cg));
244
generateShiftRightImmediate(cg, node, temp3Reg, temp3Reg, card_size_shift, true);
245
armLoadConstant(node, CARD_DIRTY, temp2Reg, cg);
246
generateMemSrc1Instruction(cg, TR::InstOpCode::strb, node, new (cg->trHeapMemory()) TR::MemoryReference(temp1Reg, temp3Reg, 1, cg), temp2Reg);
247
248
generateLabelInstruction(cg, TR::InstOpCode::label, node, noChkLabel, deps);
249
}
250
251
}
252
253
254
void
255
J9::ARM::TreeEvaluator::generateTestAndReportFieldWatchInstructions(TR::CodeGenerator *cg, TR::Node *node, TR::Snippet *dataSnippet, bool isWrite, TR::Register *sideEffectRegister, TR::Register *valueReg, TR::Register *dataSnippetRegister)
256
{
257
TR_ASSERT_FATAL(false, "This helper implements platform specific code for Fieldwatch, which is currently not supported on ARM platforms.\n");
258
}
259
260
void
261
J9::ARM::TreeEvaluator::generateFillInDataBlockSequenceForUnresolvedField(TR::CodeGenerator *cg, TR::Node *node, TR::Snippet *dataSnippet, bool isWrite, TR::Register *sideEffectRegister, TR::Register *dataSnippetRegister)
262
{
263
TR_ASSERT_FATAL(false, "This helper implements platform specific code for Fieldwatch, which is currently not supported on ARM platforms.\n");
264
}
265
266
/**
267
* \brief
268
* Generates write barrier for non-simple arraycopy node
269
*
270
* \parm srcObjReg
271
* Register for source object
272
*
273
* \parm dstObjReg
274
* Register for destination object
275
*/
276
void J9::ARM::TreeEvaluator::genWrtbarForArrayCopy(TR::Node *node, TR::Register *srcObjReg, TR::Register *dstObjReg, TR::CodeGenerator *cg)
277
{
278
TR::Compilation * comp = cg->comp();
279
bool ageCheckIsNeeded = false;
280
bool cardMarkIsNeeded = false;
281
auto gcMode = TR::Compiler->om.writeBarrierType();
282
283
ageCheckIsNeeded = (gcMode == gc_modron_wrtbar_oldcheck || gcMode == gc_modron_wrtbar_cardmark_and_oldcheck || gcMode == gc_modron_wrtbar_always);
284
cardMarkIsNeeded = (gcMode == gc_modron_wrtbar_cardmark || gcMode == gc_modron_wrtbar_cardmark_incremental);
285
286
if (!ageCheckIsNeeded && !cardMarkIsNeeded)
287
{
288
return;
289
}
290
291
if (ageCheckIsNeeded)
292
{
293
TR::Register *temp1Reg;
294
TR::Register *temp2Reg;
295
TR::RegisterDependencyConditions *conditions;
296
297
TR::LabelSymbol *doneLabel;
298
TR::SymbolReference *wbRef = comp->getSymRefTab()->findOrCreateWriteBarrierBatchStoreSymbolRef(comp->getMethodSymbol());
299
300
if (gcMode != gc_modron_wrtbar_always)
301
{
302
temp1Reg = cg->allocateRegister();
303
temp2Reg = cg->allocateRegister();
304
doneLabel = generateLabelSymbol(cg);
305
306
conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(3, 3, cg->trMemory());
307
TR::addDependency(conditions, temp1Reg, TR::RealRegister::NoReg, TR_GPR, cg);
308
TR::addDependency(conditions, temp2Reg, TR::RealRegister::NoReg, TR_GPR, cg);
309
310
TR::Register *metaReg = cg->getMethodMetaDataRegister();
311
312
// temp1Reg = dstObjReg - heapBaseForBarrierRange0
313
generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, temp1Reg,
314
new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, heapBaseForBarrierRange0), cg));
315
generateTrg1Src2Instruction(cg, TR::InstOpCode::sub, node, temp1Reg, dstObjReg, temp1Reg);
316
317
// if (temp1Reg >= heapSizeForBarrierRange0), object not in the tenured area
318
generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, temp2Reg,
319
new (cg->trHeapMemory()) TR::MemoryReference(metaReg, offsetof(J9VMThread, heapSizeForBarrierRange0), cg));
320
generateSrc2Instruction(cg, TR::InstOpCode::cmp, node, temp1Reg, temp2Reg);
321
generateConditionalBranchInstruction(cg, node, ARMConditionCodeCS, doneLabel);
322
}
323
else
324
{
325
conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(1, 1, cg->trMemory());
326
}
327
328
TR::addDependency(conditions, dstObjReg, TR::RealRegister::gr0, TR_GPR, cg);
329
330
TR::Instruction *gcPoint = generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)wbRef->getSymbol()->castToMethodSymbol()->getMethodAddress(), NULL, wbRef);
331
gcPoint->ARMNeedsGCMap(0xFFFFFFFF);
332
333
if (gcMode != gc_modron_wrtbar_always)
334
{
335
generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, conditions);
336
}
337
338
cg->machine()->setLinkRegisterKilled(true);
339
cg->setHasCall();
340
341
if (gcMode != gc_modron_wrtbar_always)
342
{
343
cg->stopUsingRegister(temp1Reg);
344
cg->stopUsingRegister(temp2Reg);
345
}
346
}
347
else if (cardMarkIsNeeded)
348
{
349
if (!comp->getOptions()->realTimeGC())
350
{
351
TR::Register *temp1Reg = cg->allocateRegister();
352
TR::Register *temp2Reg = cg->allocateRegister();
353
TR::Register *temp3Reg = cg->allocateRegister();
354
TR::RegisterDependencyConditions *conditions = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(4, 4, cg->trMemory());
355
356
TR::addDependency(conditions, dstObjReg, TR::RealRegister::NoReg, TR_GPR, cg);
357
TR::addDependency(conditions, temp1Reg, TR::RealRegister::NoReg, TR_GPR, cg);
358
TR::addDependency(conditions, temp2Reg, TR::RealRegister::NoReg, TR_GPR, cg);
359
TR::addDependency(conditions, temp3Reg, TR::RealRegister::NoReg, TR_GPR, cg);
360
361
VMCardCheckEvaluator(node, dstObjReg, temp1Reg, temp2Reg, temp3Reg, conditions, cg);
362
363
cg->stopUsingRegister(temp1Reg);
364
cg->stopUsingRegister(temp2Reg);
365
cg->stopUsingRegister(temp3Reg);
366
}
367
else
368
TR_ASSERT(0, "genWrtbarForArrayCopy card marking not supported for RT");
369
}
370
}
371
372