Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/codegen/CodeGenGC.cpp
6000 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
#if defined(J9ZOS390)
24
//On zOS XLC linker can't handle files with same name at link time
25
//This workaround with pragma is needed. What this does is essentially
26
//give a different name to the codesection (csect) for this file. So it
27
//doesn't conflict with another file with same name.
28
29
#pragma csect(CODE,"TRJ9CGGCBase#C")
30
#pragma csect(STATIC,"TRJ9CGGCBase#S")
31
#pragma csect(TEST,"TRJ9CGGCBase#T")
32
#endif
33
34
#include "codegen/J9CodeGenerator.hpp" // IWYU pragma: keep
35
36
#include <stdint.h>
37
#include <string.h>
38
#include "env/StackMemoryRegion.hpp"
39
#include "codegen/CodeGenerator.hpp"
40
#include "codegen/CodeGenerator_inlines.hpp"
41
#include "codegen/GCStackAtlas.hpp"
42
#include "codegen/GCStackMap.hpp"
43
#include "codegen/Linkage.hpp"
44
#include "codegen/Linkage_inlines.hpp"
45
#include "compile/Compilation.hpp"
46
#include "control/Options.hpp"
47
#include "control/Options_inlines.hpp"
48
#include "env/ObjectModel.hpp"
49
#include "env/CompilerEnv.hpp"
50
#include "env/TRMemory.hpp"
51
#include "env/jittypes.h"
52
#include "il/AutomaticSymbol.hpp"
53
#include "il/Node.hpp"
54
#include "il/ParameterSymbol.hpp"
55
#include "il/ResolvedMethodSymbol.hpp"
56
#include "il/Symbol.hpp"
57
#include "il/SymbolReference.hpp"
58
#include "infra/Assert.hpp"
59
#include "infra/BitVector.hpp"
60
#include "infra/IGNode.hpp"
61
#include "infra/InterferenceGraph.hpp"
62
#include "infra/List.hpp"
63
#include "ras/Debug.hpp"
64
65
void
66
J9::CodeGenerator::createStackAtlas()
67
{
68
// Assign a GC map index to each reference parameter and each reference local.
69
// Stack mapping will have to map the stack in a way that honours these indices
70
//
71
TR::Compilation *comp = self()->comp();
72
TR::ResolvedMethodSymbol * methodSymbol = comp->getMethodSymbol();
73
74
const bool doLocalsCompaction = self()->getLocalsIG() && self()->getSupportsCompactedLocals();
75
76
// From hereon, any stack memory allocations will expire / die when the function returns
77
//
78
TR::StackMemoryRegion stackMemoryRegion(*self()->trMemory());
79
80
// --------------------------------------------------------------------------------
81
// First map the parameters - the mapping of parameters is constrained by
82
// the linkage, so we depend on whether the linkage maps the parameters
83
// right to left or left to right.
84
// We assume that the parameters are mapped contiguously
85
//
86
ListIterator<TR::ParameterSymbol> parameterIterator(&methodSymbol->getParameterList());
87
TR::ParameterSymbol *parmCursor;
88
89
intptr_t stackSlotSize = TR::Compiler->om.sizeofReferenceAddress();
90
int32_t sizeOfParameterAreaInBytes = methodSymbol->getNumParameterSlots() * stackSlotSize;
91
int32_t firstMappedParmOffsetInBytes;
92
int32_t parmOffsetInBytes;
93
int32_t numParmSlots;
94
95
// Compute:
96
//
97
// 1) The offset of the first reference parameter, and
98
// 2) The total range of slots between the first parameter that contains a
99
// collected reference and the last slot that contains a collected
100
// reference.
101
//
102
// Both quantities must be positive values or 0.
103
//
104
if (comp->getOption(TR_MimicInterpreterFrameShape))
105
{
106
firstMappedParmOffsetInBytes = 0;
107
numParmSlots = methodSymbol->getNumParameterSlots();
108
}
109
else
110
{
111
firstMappedParmOffsetInBytes = sizeOfParameterAreaInBytes;
112
int32_t lastMappedParmOffsetInBytes = -1;
113
114
for (parmCursor = parameterIterator.getFirst(); parmCursor; parmCursor = parameterIterator.getNext())
115
{
116
if ((parmCursor->isReferencedParameter() || comp->getOption(TR_FullSpeedDebug)) && parmCursor->isCollectedReference())
117
{
118
parmOffsetInBytes = parmCursor->getParameterOffset();
119
120
if (!_bodyLinkage->getRightToLeft())
121
{
122
parmOffsetInBytes = sizeOfParameterAreaInBytes - parmOffsetInBytes - stackSlotSize;
123
}
124
125
if (parmOffsetInBytes < firstMappedParmOffsetInBytes)
126
{
127
firstMappedParmOffsetInBytes = parmOffsetInBytes;
128
}
129
130
if (parmOffsetInBytes > lastMappedParmOffsetInBytes)
131
{
132
lastMappedParmOffsetInBytes = parmOffsetInBytes;
133
}
134
}
135
}
136
137
if (lastMappedParmOffsetInBytes >= firstMappedParmOffsetInBytes)
138
{
139
// The range of stack slots between the first and last parameter that
140
// contain a collected references.
141
//
142
numParmSlots = ((lastMappedParmOffsetInBytes-firstMappedParmOffsetInBytes)/stackSlotSize) + 1;
143
}
144
else
145
{
146
// No collected reference parameters.
147
//
148
numParmSlots = 0;
149
}
150
}
151
152
TR_ASSERT(firstMappedParmOffsetInBytes >= 0, "firstMappedParmOffsetInBytes must be positive or 0");
153
TR_ASSERT(numParmSlots >= 0, "numParmSlots must be positive or 0");
154
155
// --------------------------------------------------------------------------------
156
// Construct the parameter map for mapped reference parameters
157
//
158
TR_GCStackMap *parameterMap = new (self()->trHeapMemory(), numParmSlots) TR_GCStackMap(numParmSlots);
159
160
// --------------------------------------------------------------------------------
161
// Now assign GC map indices to parameters depending on the linkage mapping.
162
// At the same time populate the parameter map.
163
//
164
165
// slotIndex is the zero-based index into the GC map bit vector for a reference
166
// parameter or auto.
167
//
168
int32_t slotIndex = 0;
169
170
parameterIterator.reset();
171
for (parmCursor = parameterIterator.getFirst(); parmCursor; parmCursor = parameterIterator.getNext())
172
{
173
if (comp->getOption(TR_MimicInterpreterFrameShape) || comp->getOption(TR_FullSpeedDebug))
174
{
175
parmCursor->setParmHasToBeOnStack();
176
}
177
178
if ((parmCursor->isReferencedParameter() || comp->getOption(TR_MimicInterpreterFrameShape) || comp->getOption(TR_FullSpeedDebug)) &&
179
parmCursor->isCollectedReference())
180
{
181
parmOffsetInBytes = parmCursor->getParameterOffset();
182
if (!_bodyLinkage->getRightToLeft())
183
{
184
parmOffsetInBytes = sizeOfParameterAreaInBytes - parmOffsetInBytes - stackSlotSize;
185
}
186
187
// Normalize the parameter offset on the stack to a zero-based index
188
// into the GC map.
189
//
190
slotIndex = (parmOffsetInBytes-firstMappedParmOffsetInBytes)/stackSlotSize;
191
parmCursor->setGCMapIndex(slotIndex);
192
193
if (parmCursor->getLinkageRegisterIndex()<0 ||
194
parmCursor->getAssignedGlobalRegisterIndex()<0 ||
195
_bodyLinkage->hasToBeOnStack(parmCursor))
196
{
197
parameterMap->setBit(slotIndex);
198
}
199
}
200
}
201
202
// At this point, slotIndex will cover either all the parameter slots or just
203
// the range of parameters that contain collected references.
204
//
205
slotIndex = numParmSlots;
206
207
// --------------------------------------------------------------------------------
208
// Now assign a GC map index to reference locals. When the stack is mapped,
209
// these locals will have to be mapped contiguously in the stack according to
210
// this index.
211
//
212
// Locals that need initialization during the method prologue are mapped first,
213
// then the ones that do not need initialization.
214
//
215
216
ListIterator<TR::AutomaticSymbol> automaticIterator(&methodSymbol->getAutomaticList());
217
TR::AutomaticSymbol * localCursor;
218
219
int32_t numberOfPendingPushSlots = 0;
220
if (comp->getOption(TR_MimicInterpreterFrameShape))
221
{
222
for (localCursor = automaticIterator.getFirst(); localCursor; localCursor = automaticIterator.getNext())
223
{
224
int32_t assignedIndex = localCursor->getGCMapIndex();
225
if (assignedIndex >= 0)
226
{
227
int32_t nextIndex = assignedIndex + TR::Symbol::convertTypeToNumberOfSlots(localCursor->getDataType());
228
if (nextIndex > slotIndex)
229
slotIndex = nextIndex;
230
}
231
}
232
233
// There can be holes at the end of auto list, where the auto was declared
234
// and was never used
235
//
236
if (slotIndex < methodSymbol->getFirstJitTempIndex())
237
{
238
slotIndex = methodSymbol->getFirstJitTempIndex();
239
}
240
241
numberOfPendingPushSlots = slotIndex - methodSymbol->getFirstJitTempIndex();
242
TR_ASSERT(numberOfPendingPushSlots >= 0, "assertion failure");
243
244
for (localCursor = automaticIterator.getFirst(); localCursor; localCursor = automaticIterator.getNext())
245
{
246
int32_t assignedIndex = localCursor->getGCMapIndex();
247
if (assignedIndex >= 0)
248
{
249
// FSD requires the JIT to mimic the interpreter stack.
250
// i.e. for doubles, interpreter expects 2 full slots, even on 64bit platforms.
251
// Hence, the JIT must calculate the number of slots required by interpreter and
252
// not the number of address-sized slots required to store the data type.
253
//
254
// Note: convertTypeToNumberOfSlots does not handle aggregate types,
255
// but is safe in this scenario because:
256
// 1. Symbols of aggregate types have negative GC map indices.
257
// 2. FSD runs at no-opt => no escape analysis => no aggregates.
258
//
259
localCursor->setGCMapIndex(slotIndex -
260
assignedIndex -
261
TR::Symbol::convertTypeToNumberOfSlots(localCursor->getDataType()) +
262
numParmSlots
263
);
264
if (debug("traceFSDStackMap"))
265
{
266
diagnostic("FSDStackMap: Auto moved from index %d to %d\n", assignedIndex, localCursor->getGCMapIndex());
267
}
268
}
269
}
270
}
271
272
// Iniialize colour mapping for locals compaction
273
//
274
int32_t *colourToGCIndexMap = 0;
275
276
if (doLocalsCompaction)
277
{
278
colourToGCIndexMap = (int32_t *) self()->trMemory()->allocateStackMemory(self()->getLocalsIG()->getNumberOfColoursUsedToColour() * sizeof(int32_t));
279
TR_ASSERT(colourToGCIndexMap, "Failed to allocate colourToGCIndexMap on stack");
280
281
for (int32_t i=0; i<self()->getLocalsIG()->getNumberOfColoursUsedToColour(); ++i)
282
{
283
colourToGCIndexMap[i] = -1;
284
}
285
}
286
287
// --------------------------------------------------------------------------------
288
// Map uninitialized reference locals that are not stack allocated objects
289
//
290
for (localCursor = automaticIterator.getFirst(); localCursor; localCursor = automaticIterator.getNext())
291
{
292
if (localCursor->getGCMapIndex() < 0 &&
293
localCursor->isCollectedReference() &&
294
!localCursor->isLocalObject() &&
295
!localCursor->isInitializedReference() &&
296
!localCursor->isInternalPointer() &&
297
!localCursor->isPinningArrayPointer())
298
{
299
if (doLocalsCompaction && !localCursor->holdsMonitoredObject())
300
{
301
// For reference locals that share a stack slot, make sure they get
302
// the same GC index.
303
//
304
TR_IGNode * igNode;
305
if ((igNode = self()->getLocalsIG()->getIGNodeForEntity(localCursor)) != NULL)
306
{
307
IGNodeColour colour = igNode->getColour();
308
309
if (colourToGCIndexMap[colour] == -1)
310
{
311
colourToGCIndexMap[colour] = slotIndex;
312
}
313
else
314
{
315
localCursor->setGCMapIndex(colourToGCIndexMap[colour]);
316
if (debug("traceCL"))
317
{
318
diagnostic("Shared GC index %d, ref local=%p, %s\n",
319
localCursor->getGCMapIndex(), localCursor, comp->signature());
320
}
321
322
continue;
323
}
324
}
325
}
326
327
localCursor->setGCMapIndex(slotIndex);
328
slotIndex += localCursor->getNumberOfSlots();
329
}
330
}
331
332
int32_t numberOfSlotsToBeInitialized = slotIndex - numParmSlots;
333
334
// --------------------------------------------------------------------------------
335
// Map initialized reference locals and stack allocated objects
336
//
337
int32_t numLocalObjectPaddingSlots = 0;
338
bool localObjectsFound = false;
339
340
for (localCursor = automaticIterator.getFirst(); localCursor; localCursor = automaticIterator.getNext())
341
{
342
if (localCursor->getGCMapIndex() < 0 &&
343
localCursor->isCollectedReference() &&
344
(localCursor->isLocalObject() || localCursor->isInitializedReference()) &&
345
!localCursor->isInternalPointer() &&
346
!localCursor->isPinningArrayPointer())
347
{
348
if (doLocalsCompaction &&
349
!localCursor->holdsMonitoredObject())
350
{
351
// For reference locals that share a stack slot, make sure they get
352
// the same GC index.
353
//
354
TR_IGNode * igNode;
355
if ((igNode = self()->getLocalsIG()->getIGNodeForEntity(localCursor)) != NULL)
356
{
357
IGNodeColour colour = igNode->getColour();
358
359
if (colourToGCIndexMap[colour] == -1)
360
{
361
colourToGCIndexMap[colour] = slotIndex;
362
}
363
else
364
{
365
localCursor->setGCMapIndex(colourToGCIndexMap[colour]);
366
367
if (debug("traceCL"))
368
{
369
diagnostic("Shared GC index %d, ref local=%p, %s\n",
370
localCursor->getGCMapIndex(), localCursor, comp->signature());
371
}
372
373
continue;
374
}
375
}
376
}
377
378
if (localCursor->isLocalObject())
379
{
380
localObjectsFound = true;
381
int32_t localObjectAlignment = comp->fej9()->getLocalObjectAlignmentInBytes();
382
if (localObjectAlignment > stackSlotSize &&
383
self()->supportsStackAllocations())
384
{
385
// We only get here in compressedrefs mode
386
int32_t gcMapIndexAlignment = localObjectAlignment / stackSlotSize;
387
int32_t remainder = (slotIndex - numParmSlots) % gcMapIndexAlignment;
388
if (remainder)
389
{
390
slotIndex += gcMapIndexAlignment - remainder;
391
numLocalObjectPaddingSlots += gcMapIndexAlignment - remainder;
392
traceMsg(comp, "GC index of local object %p is adjusted by +%d, and is %d now\n",localCursor, gcMapIndexAlignment - remainder, slotIndex);
393
}
394
}
395
}
396
397
localCursor->setGCMapIndex(slotIndex);
398
slotIndex += localCursor->getNumberOfSlots();
399
}
400
}
401
402
int32_t totalSlotsInMap = slotIndex;
403
404
// --------------------------------------------------------------------------------
405
// Construct and populate the stack map for a method. Start with all parameters
406
// and locals being live, and selectively unmark slots that are not live.
407
//
408
TR_GCStackMap * localMap = new (self()->trHeapMemory(), totalSlotsInMap) TR_GCStackMap(totalSlotsInMap);
409
localMap->copy(parameterMap);
410
411
// Set all the local references to be live
412
//
413
int32_t i;
414
for (i = numParmSlots; i < totalSlotsInMap; ++i)
415
{
416
localMap->setBit(i);
417
}
418
419
// Reset the bits for non-reference objects
420
//
421
if (comp->getOption(TR_MimicInterpreterFrameShape))
422
{
423
for (localCursor = automaticIterator.getFirst(); localCursor; localCursor = automaticIterator.getNext())
424
{
425
if (localCursor->getGCMapIndex() >= 0 &&
426
(!localCursor->isCollectedReference() ||
427
localCursor->isInternalPointer() ||
428
localCursor->isPinningArrayPointer()))
429
{
430
localMap->resetBit(localCursor->getGCMapIndex());
431
if (localCursor->getSize() > stackSlotSize)
432
{
433
localMap->resetBit(localCursor->getGCMapIndex() + 1);
434
}
435
}
436
}
437
}
438
439
// --------------------------------------------------------------------------
440
// Construct and populate the local object stack map
441
//
442
// Reset the bits for parts of local objects that are not collected slots
443
//
444
TR_GCStackAllocMap *localObjectStackMap = NULL;
445
446
if (localObjectsFound)
447
{
448
for (localCursor = automaticIterator.getFirst(); localCursor; localCursor = automaticIterator.getNext())
449
{
450
if (localCursor->isCollectedReference() && localCursor->isLocalObject())
451
{
452
TR::AutomaticSymbol * localObject = localCursor->getLocalObjectSymbol();
453
slotIndex = localObject->getGCMapIndex();
454
455
if (!localObjectStackMap)
456
{
457
localObjectStackMap = new (self()->trHeapMemory(), totalSlotsInMap) TR_GCStackAllocMap(totalSlotsInMap);
458
}
459
460
localObjectStackMap->setBit(slotIndex);
461
462
int32_t * collectedSlots = localObject->getReferenceSlots();
463
int32_t i = 0;
464
465
while (*collectedSlots > 0)
466
{
467
int32_t collectedSlotIndex = *collectedSlots;
468
469
// collectedSlotIndex is measured in terms of object field sizes,
470
// and we want GC map slot sizes, which are not necessarily the same
471
// (ie. compressed refs)
472
//
473
collectedSlotIndex = collectedSlotIndex * TR::Compiler->om.sizeofReferenceField() / stackSlotSize;
474
for ( ; i < collectedSlotIndex; ++i)
475
{
476
localMap->resetBit(slotIndex+i);
477
}
478
479
localMap->resetBit(slotIndex+i);
480
i = collectedSlotIndex+1;
481
collectedSlots++;
482
}
483
484
for ( ; i < localObject->getSize()/stackSlotSize; ++i)
485
{
486
localMap->resetBit(slotIndex+i);
487
}
488
}
489
}
490
}
491
492
self()->setMethodStackMap(localMap);
493
494
// --------------------------------------------------------------------------
495
// Now create the stack atlas
496
//
497
TR::GCStackAtlas * atlas = new (self()->trHeapMemory()) TR::GCStackAtlas(numParmSlots, totalSlotsInMap, self()->trMemory());
498
atlas->setParmBaseOffset(firstMappedParmOffsetInBytes);
499
atlas->setParameterMap(parameterMap);
500
atlas->setLocalMap(localMap);
501
atlas->setStackAllocMap(localObjectStackMap);
502
atlas->setNumberOfSlotsToBeInitialized(numberOfSlotsToBeInitialized);
503
atlas->setIndexOfFirstSpillTemp(totalSlotsInMap);
504
atlas->setInternalPointerMap(0);
505
atlas->setNumberOfPendingPushSlots(numberOfPendingPushSlots);
506
atlas->setNumberOfPaddingSlots(numLocalObjectPaddingSlots);
507
self()->setStackAtlas(atlas);
508
509
if (comp->getOption(TR_TraceCG))
510
{
511
traceMsg(comp, "totalSlotsInMap is %d, numLocalObjectPaddingSlots is %d\n", totalSlotsInMap, numLocalObjectPaddingSlots);
512
}
513
}
514
515