Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/bcutil/ConstantPoolMap.hpp
5985 views
1
/*******************************************************************************
2
* Copyright (c) 2001, 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
/*
24
* ConstantPoolMap.hpp
25
*/
26
27
#ifndef CONSTANTPOOLMAP_HPP_
28
#define CONSTANTPOOLMAP_HPP_
29
30
/* @ddr_namespace: default */
31
#include "j9comp.h"
32
#include "j9.h"
33
#include "cfr.h"
34
35
#include "BuildResult.hpp"
36
#include "ClassFileOracle.hpp"
37
#include "ROMClassCreationContext.hpp"
38
39
class BufferManager;
40
41
/*
42
* The ConstantPoolMap class handles mapping from class file constant pool indices
43
* to ROM class constant pool indices.
44
*
45
* The resulting ROM constant pool looks like this.
46
*
47
* +------------+-------------------+------------------+--------------------+
48
* | CP entry 0 | HEADER CP entries | split CP entries | FOOTER CP entries |
49
* +------------+-------------------+------------------+--------------------+
50
*
51
* The CP entry at index 0 is reserved - as it has a special meaning (e.g. null).
52
*
53
* The HEADER CP entries are those that must be at the beginning of the constant pool.
54
* These are required to be at the beginning because they are indexed by U_8 (and must
55
* thus be within the first 256 values). These entries are referred by 'ldc' bytecode,
56
* and since only these entries can have objects, storing them together improves
57
* the locality of objects in the heap.
58
*
59
* The FOOTER CP entries are the ones that must be at the end of the constant pool.
60
* The FOOTER entries are constants that do not need runtime-resolution, and thus
61
* do not get included in the RAM constant pool.
62
*
63
* All other CP entries are in the middle. A single CP entry in the class file may be split
64
* into multiple ROM (and consequently RAM) CP entries. This is done because a single constant
65
* pool entry may be used for different purposes, and thus requires a different value when it
66
* is resolved in the RAM constant pool. The ROM and RAM constant pools are parallel except
67
* for the FOOTER CP entries, which do not get included in the RAM constant pool.
68
*
69
* For example, suppose that during the marking phase a MethodRef constant pool entry has been
70
* marked that it is used by both invoke virtual and invoke special. Since the RAM constant pool
71
* contents for a MethodRef entry will be different based on how it's used - it is necessary that
72
* the original constant pool entry be split into (in this case) two constant pool entries and
73
* that the constant pool indices in the byte code be mapped to the reflect this.
74
*
75
* Each SPLIT* type (see EntryFlags) indicates a different SPLIT 'slot'. Concrete uses of these
76
* are specified by EntryUseFlags. All uses for a single SPLIT type must be mutually exclusive.
77
*
78
* A split constant pool entry will occupy consecutive constant pool slots for its different
79
* splits. For example, if class file constant pool entry 12 was marked with SPLIT1, SPLIT2 and
80
* SPLIT4 flags, then it will map to the following indices in the ROM constant pool:
81
*
82
* _constantPoolEntries[12].romCPBaseIndex for SPLIT1
83
* _constantPoolEntries[12].romCPBaseIndex + 1 for SPLIT2
84
* _constantPoolEntries[12].romCPBaseIndex + 2 for SPLIT4
85
*
86
* The above can be queried by using the getROMClassCPIndex() function after all marking is done.
87
*/
88
class ConstantPoolMap
89
{
90
public:
91
92
class ConstantPoolVisitor
93
{
94
public:
95
virtual void visitClass(U_16 cfrCPIndex) = 0;
96
virtual void visitString(U_16 cfrCPIndex) = 0;
97
virtual void visitMethodType(U_16 cfrCPIndex, U_16 forMethodHandleInvocation) = 0;
98
virtual void visitMethodHandle(U_16 kind, U_16 cfrCPIndex) = 0;
99
virtual void visitConstantDynamic(U_16 bsmIndex, U_16 cfrCPIndex, U_32 primitiveFlag) = 0;
100
virtual void visitSingleSlotConstant(U_32 slot1) = 0;
101
virtual void visitDoubleSlotConstant(U_32 slot1, U_32 slot2) = 0;
102
virtual void visitFieldOrMethod(U_16 classRefCPIndex, U_16 nameAndSignatureCfrCPIndex) = 0;
103
};
104
105
class ConstantPoolEntryTypeVisitor
106
{
107
public:
108
virtual void visitEntryType(U_32 entryType) = 0;
109
};
110
111
struct CallSiteVisitor
112
{
113
virtual void visitCallSite(U_16 nameAndSignatureCfrCPIndex, U_16 bootstrapMethodIndex) = 0;
114
};
115
116
struct SplitEntryVisitor
117
{
118
virtual void visitSplitEntry(U_16 cpIndex) = 0;
119
};
120
121
ConstantPoolMap(BufferManager *bufferManager, ROMClassCreationContext *context);
122
~ConstantPoolMap();
123
124
void setClassFileOracleAndInitialize(ClassFileOracle *classFileOracle);
125
126
void computeConstantPoolMapAndSizes();
127
128
#if defined(J9VM_OPT_METHOD_HANDLE)
129
void findVarHandleMethodRefs();
130
#endif /* defined(J9VM_OPT_METHOD_HANDLE) */
131
132
bool isOK() const { return OK == _buildResult; }
133
BuildResult getBuildResult() const { return _buildResult; }
134
135
void constantPoolDo(ConstantPoolVisitor *visitor);
136
void constantPoolEntryTypesDo(ConstantPoolEntryTypeVisitor *visitor)
137
{
138
for (UDATA i = 1; i < _romConstantPoolCount; i++) {
139
visitor->visitEntryType(_romConstantPoolTypes[i]);
140
}
141
}
142
143
void callSitesDo(CallSiteVisitor *visitor)
144
{
145
U_16 constantPoolCount = _classFileOracle->getConstantPoolCount();
146
for (U_16 i = 0; i < constantPoolCount; ++i) {
147
U_32 callSiteReferenceCount = _constantPoolEntries[i].callSiteReferenceCount;
148
for (U_32 j = 0; j < callSiteReferenceCount; ++j) {
149
visitor->visitCallSite(U_16(getCPSlot2(i)), U_16(getCPSlot1(i)));
150
}
151
}
152
}
153
154
void staticSplitEntriesDo(SplitEntryVisitor *visitor)
155
{
156
for (U_16 i = 0; i < _staticSplitEntryCount; i++) {
157
visitor->visitSplitEntry(_staticSplitEntries[i]);
158
}
159
}
160
161
void specialSplitEntriesDo(SplitEntryVisitor *visitor)
162
{
163
for (U_16 i = 0; i < _specialSplitEntryCount; i++) {
164
visitor->visitSplitEntry(_specialSplitEntries[i]);
165
}
166
}
167
168
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
169
U_32 getInvokeCacheCount() const { return _invokeCacheCount; }
170
#else /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */
171
U_32 getMethodTypeCount() const { return _methodTypeCount; }
172
U_32 getVarHandleMethodTypeCount() const { return _varHandleMethodTypeCount; }
173
U_32 getVarHandleMethodTypePaddedCount() const { return _varHandleMethodTypeCount + (_varHandleMethodTypeCount & 0x1); /* Rounding up to an even number */ }
174
U_16 *getVarHandleMethodTypeLookupTable() const { return _varHandleMethodTypeLookupTable; }
175
#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */
176
U_32 getCallSiteCount() const { return _callSiteCount; }
177
U_16 getRAMConstantPoolCount() const { return _ramConstantPoolCount; }
178
U_16 getROMConstantPoolCount() const { return _romConstantPoolCount; }
179
U_16 getStaticSplitEntryCount() const { return _staticSplitEntryCount; }
180
U_16 getSpecialSplitEntryCount() const { return _specialSplitEntryCount; }
181
182
U_16 getROMClassCPIndex(U_16 cfrCPIndex, UDATA splitType) const
183
{
184
return _constantPoolEntries[cfrCPIndex].romCPIndex;
185
}
186
U_16 getROMClassCPIndex(U_16 cfrCPIndex) const { return getROMClassCPIndex(cfrCPIndex, 0); }
187
188
/*
189
* Note: InvokeDynamicInfo CP entries are not marked in the same way as other CP entries. In particular,
190
* isMarked(cfrCPIndex, INVOKE_DYNAMIC) is always false. The correct check is
191
* computeConstantPoolMapAndSizes, is (0 != _constantPoolEntries[cfrCPIndex].callSiteReferenceCount).
192
*/
193
U_16 getCallSiteIndex(U_16 cfrCPIndex)
194
{
195
U_16 romClassCPIndex = getROMClassCPIndex(cfrCPIndex);
196
U_16 index = _constantPoolEntries[cfrCPIndex].currentCallSiteIndex++;
197
Trc_BCU_Assert_True(index < _constantPoolEntries[cfrCPIndex].callSiteReferenceCount);
198
return romClassCPIndex + index;
199
}
200
201
U_16 getStaticSplitTableIndex(U_16 cfrCPIndex) { return _constantPoolEntries[cfrCPIndex].staticSplitTableIndex; }
202
U_16 getSpecialSplitTableIndex(U_16 cfrCPIndex) { return _constantPoolEntries[cfrCPIndex].specialSplitTableIndex; }
203
204
void mark(U_16 cfrCPIndex) { _constantPoolEntries[cfrCPIndex].isReferenced = true; }
205
void mark(U_16 cfrCPIndex, UDATA useType)
206
{
207
mark(cfrCPIndex);
208
_constantPoolEntries[cfrCPIndex].isUsedBy[useType] = true;
209
}
210
211
bool isMarked(U_16 cfrCPIndex) const { return _constantPoolEntries[cfrCPIndex].isReferenced; }
212
bool isMarked(U_16 cfrCPIndex, UDATA useType) const { return _constantPoolEntries[cfrCPIndex].isUsedBy[useType]; }
213
214
U_8 getCPTag(U_16 cfrCPIndex) const { return _classFileOracle->getCPTag(cfrCPIndex); }
215
U_32 getCPSlot1(U_16 cfrCPIndex) const { return _classFileOracle->getCPSlot1(cfrCPIndex); }
216
U_32 getCPSlot2(U_16 cfrCPIndex) const { return _classFileOracle->getCPSlot2(cfrCPIndex); }
217
218
U_16 getROMClassCPIndexForReference(U_16 cfrCPIndex) const { return getROMClassCPIndex(cfrCPIndex); }
219
U_16 getROMClassCPIndexForAnnotation(U_16 cfrCPIndex) const { return getROMClassCPIndex(cfrCPIndex); }
220
221
bool isUTF8ConstantReferenced(U_16 cfrCPIndex) const { return isMarked(cfrCPIndex); }
222
bool isNATConstantReferenced(U_16 cfrCPIndex) const { return isMarked(cfrCPIndex); }
223
224
bool isStaticSplit(U_16 cfrCPIndex) const
225
{
226
/* A CP index needs to be added to static split side table if any of the following is true:
227
* 1. it is shared between 'invokestatic' and 'invokeinterface' bytecodes,
228
* 2. it is shared between 'invokestatic' and 'invokespecial' bytecodes
229
*
230
* First condition is required to support 'default' methods introduced as part of JSR 335.
231
* Sharing of CP index between 'invokestatic' and 'invokespecial' can also be handled using the side table mechanism
232
* instead of marking it as J9CPTYPE_SHARED_METHOD, and hence the second condition.
233
* See Jazz103 Design 40047.
234
*/
235
return (isMarked(cfrCPIndex, INVOKE_STATIC)
236
&& (_context->alwaysSplitBytecodes()
237
|| isMarked(cfrCPIndex, INVOKE_INTERFACE)
238
|| isMarked(cfrCPIndex, INVOKE_SPECIAL)
239
#if JAVA_SPEC_VERSION >= 11
240
|| isMarked(cfrCPIndex, INVOKE_VIRTUAL)
241
#endif /* JAVA_SPEC_VERSION >= 11 */
242
));
243
}
244
245
bool isSpecialSplit(U_16 cfrCPIndex) const
246
{
247
/* A constant pool index needs to be added to special split table if
248
* it is referred by 'invokespecial' and 'invokeinterface' bytecodes.
249
* This is required to support 'default' methods introduced as part of JSR 335.
250
* See Jazz103 Design 40047.
251
*/
252
return (isMarked(cfrCPIndex, INVOKE_SPECIAL)
253
&& (_context->alwaysSplitBytecodes()
254
|| isMarked(cfrCPIndex, INVOKE_INTERFACE)
255
#if JAVA_SPEC_VERSION >= 11
256
|| isMarked(cfrCPIndex, INVOKE_VIRTUAL)
257
#endif /* JAVA_SPEC_VERSION >= 11 */
258
));
259
}
260
261
bool hasStaticSplitTable() const { return _staticSplitEntryCount != 0; }
262
bool hasSpecialSplitTable() const { return _specialSplitEntryCount != 0; }
263
264
bool hasCallSites() const { return 0 != _callSiteCount; }
265
#if defined(J9VM_OPT_METHOD_HANDLE)
266
bool hasVarHandleMethodRefs() const { return 0 != _varHandleMethodTypeCount; }
267
#endif /* defined(J9VM_OPT_METHOD_HANDLE) */
268
269
void markConstantAsReferencedDoubleSlot(U_16 cfrCPIndex) { mark(cfrCPIndex); }
270
void markConstantAsUsedByLDC(U_8 cfrCPIndex) { _constantPoolEntries[cfrCPIndex].isUsedByLDC = true; }
271
272
void markConstantAsReferenced(U_16 cfrCPIndex) { mark(cfrCPIndex, REFERENCED); }
273
274
void markConstantUTF8AsReferenced(U_16 cfrCPIndex) { mark(cfrCPIndex); }
275
void markConstantNameAndTypeAsReferenced(U_16 cfrCPIndex) { mark(cfrCPIndex); }
276
277
void markConstantAsUsedByAnnotationUTF8(U_16 cfrCPIndex) { mark(cfrCPIndex, ANNOTATION); }
278
279
void markClassAsUsedByInstanceOf(U_16 classCfrCPIndex) { mark(classCfrCPIndex, INSTANCE_OF); }
280
void markClassAsUsedByCheckCast(U_16 classCfrCPIndex) { mark(classCfrCPIndex, CHECK_CAST); }
281
void markClassAsUsedByMultiANewArray(U_16 classCfrCPIndex) { mark(classCfrCPIndex, MULTI_ANEW_ARRAY); }
282
void markClassAsUsedByANewArray(U_16 classCfrCPIndex) { mark(classCfrCPIndex, ANEW_ARRAY); }
283
void markClassAsUsedByNew(U_16 classCfrCPIndex) { mark(classCfrCPIndex, NEW); }
284
#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)
285
void markClassAsUsedByAconst_init(U_16 classCfrCPIndex) { mark(classCfrCPIndex, ACONST_INIT); }
286
void markFieldRefAsUsedByWithField(U_16 fieldRefCfrCPIndex) { mark(fieldRefCfrCPIndex, WITH_FIELD); }
287
#endif
288
289
void markFieldRefAsUsedByGetStatic(U_16 fieldRefCfrCPIndex) { mark(fieldRefCfrCPIndex, GET_STATIC); }
290
void markFieldRefAsUsedByPutStatic(U_16 fieldRefCfrCPIndex) { mark(fieldRefCfrCPIndex, PUT_STATIC); }
291
void markFieldRefAsUsedByGetField(U_16 fieldRefCfrCPIndex) { mark(fieldRefCfrCPIndex, GET_FIELD); }
292
void markFieldRefAsUsedByPutField(U_16 fieldRefCfrCPIndex) { mark(fieldRefCfrCPIndex, PUT_FIELD); }
293
294
void markMethodRefAsUsedByInvokeVirtual(U_16 methodRefCfrCPIndex) { mark(methodRefCfrCPIndex, INVOKE_VIRTUAL); }
295
void markMethodRefAsUsedByInvokeSpecial(U_16 methodRefCfrCPIndex) { mark(methodRefCfrCPIndex, INVOKE_SPECIAL); }
296
void markMethodRefAsUsedByInvokeStatic(U_16 methodRefCfrCPIndex) { mark(methodRefCfrCPIndex, INVOKE_STATIC); }
297
void markMethodRefAsUsedByInvokeInterface(U_16 methodRefCfrCPIndex) { mark(methodRefCfrCPIndex, INVOKE_INTERFACE); }
298
299
void markMethodRefAsUsedByInvokeHandle(U_16 methodRefCfrCPIndex) {
300
mark(methodRefCfrCPIndex, INVOKE_HANDLEEXACT);
301
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
302
_invokeCacheCount++;
303
#else /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */
304
_methodTypeCount++;
305
#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */
306
}
307
308
void markMethodRefAsUsedByInvokeHandleGeneric(U_16 methodRefCfrCPIndex) {
309
mark(methodRefCfrCPIndex, INVOKE_HANDLEGENERIC);
310
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
311
_invokeCacheCount++;
312
#else /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */
313
_methodTypeCount++;
314
#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */
315
}
316
317
318
void markInvokeDynamicInfoAsUsedByInvokeDynamic(U_16 cfrCPIndex)
319
{
320
/*
321
* Note: Unlike the other markFooAsUsedByBar(U_16 cfrCPIndex) methods above, uses of InvokeDynamicInfo CP entries are not marked
322
* with mark(cfrCPIndex, INVOKE_DYNAMIC) because the romCPBaseIndex for these entries is an index into the callSites table
323
* instead of the ROM Constant Pool. Also see computeConstantPoolMapAndSizes.
324
*/
325
mark(cfrCPIndex);
326
_constantPoolEntries[cfrCPIndex].callSiteReferenceCount++;
327
++_callSiteCount;
328
}
329
330
private:
331
/* TODO turn EntryFlags into static const UDATAs instead of an enum type that is never used */
332
333
/* Indices into the ConstantPoolEntry.flags bool array. See comment at the top of the file for more info. */
334
enum EntryFlags
335
{
336
SPLIT1 = 0,
337
SPLIT2 = 1,
338
SPLIT3 = 2,
339
SPLIT4 = 3,
340
SPLIT5 = 4,
341
/* SPLIT_FLAG_COUNT is the number of possible split types. */
342
SPLIT_FLAG_COUNT = 5
343
};
344
345
struct ConstantPoolEntry
346
{
347
/* If callSiteReferenceCount > 0 then romCPIndexes[0] is the Call Site base index for this entry. */
348
U_32 callSiteReferenceCount;
349
U_16 currentCallSiteIndex;
350
U_16 staticSplitTableIndex; /* maps this cpIndex to J9ROMClass.staticSplitMethodRefIndexes */
351
U_16 specialSplitTableIndex; /* maps this cpIndex to J9ROMClass.specialSplitMethodRefIndexes */
352
U_16 romCPIndex;
353
bool isUsedBy[SPLIT_FLAG_COUNT];
354
bool isReferenced;
355
bool isUsedByLDC;
356
};
357
358
ROMClassCreationContext *_context;
359
ClassFileOracle *_classFileOracle;
360
BufferManager *_bufferManager;
361
362
ConstantPoolEntry *_constantPoolEntries;
363
U_16 *_romConstantPoolEntries;
364
U_8 *_romConstantPoolTypes;
365
U_16 *_staticSplitEntries;
366
U_16 *_specialSplitEntries;
367
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
368
U_32 _invokeCacheCount;
369
#else /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */
370
U_32 _methodTypeCount;
371
U_16 _varHandleMethodTypeCount;
372
U_16 *_varHandleMethodTypeLookupTable;
373
#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */
374
U_32 _callSiteCount;
375
U_16 _ramConstantPoolCount;
376
U_16 _romConstantPoolCount;
377
U_16 _staticSplitEntryCount;
378
U_16 _specialSplitEntryCount;
379
BuildResult _buildResult;
380
381
public:
382
383
/* Specific flags that are aliases for EntryFlags constants. See comment at the top of the file for more info. */
384
enum EntryUseFlags
385
{
386
REFERENCED = SPLIT1,
387
LDC2W = SPLIT1,
388
PUT_STATIC = SPLIT1,
389
GET_STATIC = SPLIT1,
390
PUT_FIELD = SPLIT1,
391
GET_FIELD = SPLIT1,
392
#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)
393
ACONST_INIT = SPLIT1,
394
WITH_FIELD = SPLIT1,
395
#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */
396
NEW = SPLIT1,
397
INVOKE_HANDLEGENERIC = SPLIT5,
398
INVOKE_HANDLEEXACT = SPLIT5,
399
INVOKE_STATIC = SPLIT4,
400
INVOKE_SPECIAL = SPLIT3,
401
INVOKE_VIRTUAL = SPLIT2,
402
INVOKE_INTERFACE = SPLIT1,
403
ANEW_ARRAY = SPLIT1,
404
CHECK_CAST = SPLIT1,
405
INSTANCE_OF = SPLIT1,
406
MULTI_ANEW_ARRAY = SPLIT1,
407
ANNOTATION = SPLIT1,
408
/* INVOKE_DYNAMIC does not use a constant pool entry. It is used only for ClassFileOracle::BytecodeFixupEntry.type. */
409
INVOKE_DYNAMIC = SPLIT_FLAG_COUNT,
410
/* LDC does not use a constant pool entry. It is used only for ClassFileOracle::BytecodeFixupEntry.type. */
411
LDC = SPLIT_FLAG_COUNT + 1
412
};
413
414
};
415
416
#endif /* CONSTANTPOOLMAP_HPP_ */
417
418