Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/sourcetools/j9constantpool/com/ibm/oti/VMCPTool/ConstantPoolStream.java
6004 views
1
/*******************************************************************************
2
* Copyright (c) 2004, 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
package com.ibm.oti.VMCPTool;
23
24
import java.io.PrintWriter;
25
import java.nio.charset.StandardCharsets;
26
import java.util.ArrayList;
27
import java.util.Collections;
28
import java.util.HashMap;
29
import java.util.Iterator;
30
import java.util.List;
31
import java.util.Map;
32
import java.util.Set;
33
34
// The ConstantPoolStream class is a little ugly because it captures and writes state in 2 passes.
35
// The two passes should consist of exactly the same sequence of calls to write*(). The first pass
36
// captures offsets that may be "forward references". The second pass then provides correct offsets
37
// of ConstantPoolItems from getOffset(ConstantPoolItem).
38
//
39
// The size of the constant pool is captured from the offset when open() is called. The offset is
40
// then reset to 0. Buffers are flushed and the output stream is attached.
41
//
42
// Thus a correct call sequence would be something like:
43
// ConstantPoolStream s = new ConstantPoolStream("jcl", constantPool, itemCount);
44
// /* First sequence of s.writeByte() and friends */
45
// s.open(out);
46
// /* Second sequence of s.writeByte() and friends */
47
// s.close();
48
49
@SuppressWarnings("nls")
50
public class ConstantPoolStream {
51
public final int version;
52
public final Set<String> flags;
53
private final List<byte[]> outputQueue = new ArrayList<>();
54
private ConstantPool constantPool;
55
private int[] cpDescription;
56
private PrintWriter out;
57
private int offset;
58
private int itemCount;
59
private boolean even = true;
60
61
// These constants are taken from j9.h
62
private static final int J9CPTYPE_UNUSED = 0;
63
private static final int J9CPTYPE_CLASS = 1;
64
private static final int J9CPTYPE_INSTANCE_FIELD = 7;
65
private static final int J9CPTYPE_STATIC_FIELD = 8;
66
private static final int J9CPTYPE_VIRTUAL_METHOD = 9;
67
private static final int J9CPTYPE_STATIC_METHOD = 10;
68
private static final int J9CPTYPE_SPECIAL_METHOD = 11;
69
private static final int J9CPTYPE_INTERFACE_METHOD = 12;
70
private static final int J9_CP_BITS_PER_DESCRIPTION = 8;
71
private static final int J9_CP_DESCRIPTION_MASK = 0xff;
72
private static final int J9_CP_DESCRIPTIONS_PER_U32 = 4;
73
74
public static final int ITEM_SIZE = 8; // Bytes per Constant Pool Item
75
76
public ConstantPoolStream(int version, Set<String> flags, ConstantPool constantPool, int itemCount) {
77
this.version = version;
78
this.flags = Collections.unmodifiableSet(flags);
79
this.constantPool = constantPool;
80
this.itemCount = itemCount;
81
this.cpDescription = new int[(itemCount + J9_CP_DESCRIPTIONS_PER_U32 - 1) / J9_CP_DESCRIPTIONS_PER_U32];
82
83
// Initialize constant pool descriptors
84
for (int i = 0; i < itemCount; i++) {
85
mark(i, J9CPTYPE_UNUSED);
86
}
87
}
88
89
private void mark(int cpIndex, int type) {
90
int index = cpIndex / J9_CP_DESCRIPTIONS_PER_U32;
91
int shift = (cpIndex % J9_CP_DESCRIPTIONS_PER_U32) * J9_CP_BITS_PER_DESCRIPTION;
92
cpDescription[index] |= (type & J9_CP_DESCRIPTION_MASK) << shift;
93
}
94
95
private void mark(int type) {
96
if (0 != offset % ITEM_SIZE) {
97
throw new Error("Constant Pool offset is not Item-aligned");
98
}
99
100
mark(offset / ITEM_SIZE, type);
101
}
102
103
public void markInstanceField() {
104
mark(J9CPTYPE_INSTANCE_FIELD);
105
}
106
107
public void markStaticField() {
108
mark(J9CPTYPE_STATIC_FIELD);
109
}
110
111
public void markStaticMethod() {
112
mark(J9CPTYPE_STATIC_METHOD);
113
}
114
115
public void markVirtualMethod() {
116
mark(J9CPTYPE_VIRTUAL_METHOD);
117
}
118
119
public void markSpecialMethod() {
120
mark(J9CPTYPE_SPECIAL_METHOD);
121
}
122
123
public void markInterfaceMethod() {
124
mark(J9CPTYPE_INTERFACE_METHOD);
125
}
126
127
public void markClass() {
128
mark(J9CPTYPE_CLASS);
129
}
130
131
public void writeBoolean(boolean arg0) {
132
writeByte(arg0 ? 1 : 0);
133
}
134
135
public void writeByte(int arg0) {
136
write(new byte[] { (byte) arg0 });
137
}
138
139
public void writeBytes(String arg0) {
140
throw new UnsupportedOperationException("writeBytes not supported");
141
}
142
143
public void writeChar(int arg0) {
144
writeShort((short) arg0);
145
}
146
147
public void writeChars(String arg0) {
148
throw new UnsupportedOperationException("writeChars not supported");
149
}
150
151
public void writeDouble(double arg0) {
152
writeLong(Double.doubleToLongBits(arg0));
153
}
154
155
public void writeFloat(float arg0) {
156
writeInt(Float.floatToIntBits(arg0));
157
}
158
159
public void writeInt(int arg0) {
160
write(new byte[] { (byte) (arg0 >> 24), (byte) (arg0 >> 16), (byte) (arg0 >> 8), (byte) arg0 });
161
}
162
163
public void writeLong(long arg0) {
164
write(new byte[] {
165
(byte) (arg0 >> 56), (byte) (arg0 >> 48), (byte) (arg0 >> 40), (byte) (arg0 >> 32),
166
(byte) (arg0 >> 24), (byte) (arg0 >> 16), (byte) (arg0 >> 8), (byte) arg0 });
167
}
168
169
public void writeShort(int arg0) {
170
write(new byte[] { (byte) (arg0 >> 8), (byte) arg0 });
171
}
172
173
public void writeUTF(String arg0) {
174
byte[] data = arg0.getBytes(StandardCharsets.UTF_8);
175
for (int i = 0; i < data.length; i++) {
176
writeByte(data[i]);
177
}
178
}
179
180
/**
181
* Add the specified bytes to the constant pool.
182
* The bytes must be in big endian order. They will
183
* be reversed on little endian platforms.
184
*/
185
protected void write(byte[] data) {
186
if (null != out) {
187
outputQueue.add(data);
188
if (data.length == 4) {
189
flushQueue();
190
}
191
}
192
193
offset += data.length;
194
}
195
196
public int getOffset() {
197
return offset;
198
}
199
200
public void alignTo(int alignment) {
201
while ((getOffset() % alignment) != 0) {
202
writeByte(0);
203
}
204
}
205
206
private void flushQueue() {
207
for (Iterator<byte[]> iter = outputQueue.iterator(); iter.hasNext();) {
208
if (even) {
209
out.print("\t\t{");
210
}
211
212
byte[] r0 = iter.next();
213
if (r0.length == 4) {
214
out.print(hex(r0));
215
} else {
216
byte[] r1 = iter.next();
217
if (r0.length == 2 && r1.length == 2) {
218
out.print("WORD_WORD(" + hex(r0) + ", " + hex(r1) + ")");
219
} else {
220
byte[] r2 = iter.next();
221
if (r0.length == 2 && r1.length == 1 && r2.length == 1) {
222
out.print("WORD_BYTE_BYTE(" + hex(r0) + ", " + hex(r1) + ", " + hex(r2) + ")");
223
} else if (r0.length == 1 && r1.length == 1 && r2.length == 2) {
224
out.print("BYTE_BYTE_WORD(" + hex(r0) + ", " + hex(r1) + ", " + hex(r2) + ")");
225
} else {
226
byte[] r3 = iter.next();
227
if (r0.length == 1 && r1.length == 1 && r2.length == 1 && r3.length == 1) {
228
out.print("BYTE_BYTE_BYTE_BYTE(" + hex(r0) + ", " + hex(r1) + ", " + hex(r2) + ", " + hex(r3) + ")");
229
} else {
230
throw new Error();
231
}
232
}
233
}
234
}
235
236
if (even) {
237
out.print(", ");
238
} else {
239
out.println("},");
240
}
241
even = !even;
242
}
243
outputQueue.clear();
244
}
245
246
private static final String HEX = "0123456789ABCDEF";
247
248
private static String hex(byte[] array) {
249
StringBuilder buffer = new StringBuilder(array.length * 2 + 2);
250
251
buffer.append("0x");
252
253
for (int i = 0; i < array.length; i++) {
254
buffer.append(HEX.charAt((array[i] >> 4) & 0x0F));
255
buffer.append(HEX.charAt((array[i] >> 0) & 0x0F));
256
}
257
258
return buffer.toString();
259
}
260
261
private final Map<ConstantPoolItem, Offset> secondaryItems = new HashMap<>();
262
263
private class Offset {
264
final int offset;
265
final boolean wrote;
266
267
Offset(int offset, boolean wrote) {
268
this.offset = offset;
269
this.wrote = wrote;
270
}
271
}
272
273
public void writeSecondaryItem(ConstantPoolItem item) {
274
// We "write" the secondary item if it hasn't been previously seen or written.
275
// The secondary item can only have been written if there is an output stream.
276
Offset offset = secondaryItems.get(item);
277
if (null == offset || (null != out && !offset.wrote)) {
278
item.write(this);
279
}
280
}
281
282
public void setOffset(ConstantPoolItem item) {
283
Offset offset = secondaryItems.get(item);
284
if (null != offset && getOffset() != offset.offset) {
285
throw new Error("Mismatched offset in secondary item");
286
}
287
secondaryItems.put(item, new Offset(getOffset(), null != out));
288
}
289
290
public int getOffset(ConstantPoolItem item) {
291
Offset offset = secondaryItems.get(item);
292
return null == offset ? -1 : offset.offset;
293
}
294
295
public void open(PrintWriter out) {
296
int size = offset;
297
offset = 0;
298
outputQueue.clear();
299
this.out = out;
300
writeHeader(size);
301
}
302
303
public void close() {
304
flushQueue();
305
writeFooter();
306
}
307
308
private void writeFooter() {
309
out.println("\t},");
310
writeUnsplitDescription();
311
out.println("};");
312
out.println();
313
out.println("const J9ROMClass * jclROMClass = &_jclROMClass.romClass;");
314
}
315
316
private void writeHeader(int size) {
317
if (null != out) {
318
if (0 == size || 0 != size % ConstantPoolStream.ITEM_SIZE) {
319
throw new Error("Constant Pool size is not Item-aligned");
320
}
321
322
int totalCPSize = size / ConstantPoolStream.ITEM_SIZE;
323
324
out.println("static const struct {");
325
out.println("\tJ9ROMClass romClass;");
326
out.println("\tJ9ROMConstantPoolItem romConstantPool[" + totalCPSize + "];");
327
out.println("\tU_32 cpDescription[" + cpDescription.length + "];");
328
out.println("} _jclROMClass = {");
329
330
String shapeDescriptionOffset = "sizeof(J9ROMClass) - offsetof(J9ROMClass, cpShapeDescription) + " + size;
331
out.println("\t{0,0,0,0,0,J9AccClassUnsafe, 0,0,0,0,0,0,0,0, " + itemCount + ", " + itemCount + ", 0,0,0, " + shapeDescriptionOffset + ", 0,},");
332
out.println("\t{");
333
}
334
}
335
336
private void writeUnsplitDescription() {
337
final int J9CPTYPE_FIELD = 7;
338
final int J9CPTYPE_INSTANCE_METHOD = 9;
339
340
out.print("\t{");
341
for (int i = 0; i < cpDescription.length; i++) {
342
int descriptionWord = cpDescription[i];
343
for (int j = 0; j < J9_CP_DESCRIPTIONS_PER_U32; j++) {
344
int shift = j * J9_CP_BITS_PER_DESCRIPTION;
345
int oldNibble = (descriptionWord >>> shift) & J9_CP_DESCRIPTION_MASK;
346
int newNibble = oldNibble;
347
if ((J9CPTYPE_INSTANCE_FIELD == oldNibble) || (J9CPTYPE_STATIC_FIELD == oldNibble)) {
348
newNibble = J9CPTYPE_FIELD;
349
} else if ((J9CPTYPE_VIRTUAL_METHOD == oldNibble) || (J9CPTYPE_SPECIAL_METHOD == oldNibble)) {
350
newNibble = J9CPTYPE_INSTANCE_METHOD;
351
}
352
if (newNibble != oldNibble) {
353
descriptionWord &= ~(J9_CP_DESCRIPTION_MASK << shift);
354
descriptionWord |= (newNibble & J9_CP_DESCRIPTION_MASK) << shift;
355
}
356
}
357
out.print("0x" + Integer.toHexString(descriptionWord) + ", ");
358
}
359
out.println("}");
360
}
361
362
public int getIndex(PrimaryItem item) {
363
return constantPool.getIndex(item);
364
}
365
366
public PrimaryItem findPrimaryItem(Object obj) {
367
return constantPool.findPrimaryItem(obj);
368
}
369
370
public void comment(String string) {
371
if (null != out) {
372
out.print("\t/* " + string + " */");
373
}
374
}
375
376
}
377
378