Skip to content

Commit c5dbd35

Browse files
committed
Make heap dumping layer-aware.
1 parent ff024fb commit c5dbd35

File tree

5 files changed

+265
-94
lines changed

5 files changed

+265
-94
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/dump/HeapDumpMetadata.java

Lines changed: 115 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
*/
2525
package com.oracle.svm.core.heap.dump;
2626

27+
import java.util.EnumSet;
28+
2729
import org.graalvm.nativeimage.ImageSingletons;
2830
import org.graalvm.nativeimage.Platform;
2931
import org.graalvm.nativeimage.Platforms;
@@ -44,14 +46,18 @@
4446
import com.oracle.svm.core.heap.ObjectVisitor;
4547
import com.oracle.svm.core.heap.UnknownObjectField;
4648
import com.oracle.svm.core.hub.DynamicHub;
49+
import com.oracle.svm.core.layeredimagesingleton.InitialLayerOnlyImageSingleton;
50+
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
51+
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonSupport;
52+
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
53+
import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton;
4754
import com.oracle.svm.core.memory.NullableNativeMemory;
4855
import com.oracle.svm.core.nmt.NmtCategory;
4956
import com.oracle.svm.core.util.coder.ByteStream;
5057
import com.oracle.svm.core.util.coder.ByteStreamAccess;
5158
import com.oracle.svm.core.util.coder.NativeCoder;
5259
import com.oracle.svm.core.util.coder.Pack200Coder;
5360

54-
import jdk.graal.compiler.api.replacements.Fold;
5561
import jdk.graal.compiler.word.Word;
5662

5763
/**
@@ -95,9 +101,8 @@
95101
* |----------------------------|
96102
* </pre>
97103
*/
98-
public class HeapDumpMetadata {
104+
public class HeapDumpMetadata implements InitialLayerOnlyImageSingleton {
99105
private final ComputeHubDataVisitor computeHubDataVisitor;
100-
@UnknownObjectField(availability = AfterCompilation.class) private byte[] data;
101106

102107
private int fieldNameCount;
103108
private int classInfoCount;
@@ -110,30 +115,37 @@ public HeapDumpMetadata() {
110115
computeHubDataVisitor = new ComputeHubDataVisitor();
111116
}
112117

113-
@Fold
114118
public static HeapDumpMetadata singleton() {
115119
return ImageSingletons.lookup(HeapDumpMetadata.class);
116120
}
117121

118-
@Platforms(Platform.HOSTED_ONLY.class)
119-
public void setData(byte[] value) {
120-
this.data = value;
121-
}
122-
123122
public boolean initialize() {
124123
assert classInfos.isNull() && fieldInfoTable.isNull() && fieldNameTable.isNull();
125124

126-
Pointer start = NonmovableArrays.getArrayBase(NonmovableArrays.fromImageHeap(data));
127-
Pointer end = start.add(data.length);
125+
HeapDumpEncodedData[] encodedDataArray = HeapDumpEncodedData.layeredSingletons();
128126

129127
ByteStream stream = StackValue.get(ByteStream.class);
130-
ByteStreamAccess.initialize(stream, start);
131128

132-
/* Read the header. */
133-
int totalFieldCount = NativeCoder.readInt(stream);
134-
int classCount = NativeCoder.readInt(stream);
135-
fieldNameCount = NativeCoder.readInt(stream);
136-
int maxTypeId = Pack200Coder.readUVAsInt(stream);
129+
int totalFieldCount = 0;
130+
int totalFieldNameCount = 0;
131+
int maxTypeId = Integer.MIN_VALUE;
132+
133+
/*
134+
* First read all encoded data arrays to determine how large of data structures to allocate.
135+
*/
136+
for (HeapDumpEncodedData encodedData : encodedDataArray) {
137+
byte[] data = encodedData.data;
138+
139+
Pointer start = NonmovableArrays.getArrayBase(NonmovableArrays.fromImageHeap(data));
140+
ByteStreamAccess.initialize(stream, start);
141+
142+
/* Read the header. */
143+
totalFieldCount += NativeCoder.readInt(stream);
144+
NativeCoder.readInt(stream); // class count
145+
totalFieldNameCount += NativeCoder.readInt(stream);
146+
maxTypeId = Integer.max(Pack200Coder.readUVAsInt(stream), maxTypeId);
147+
}
148+
fieldNameCount = totalFieldNameCount;
137149
classInfoCount = maxTypeId + 1;
138150

139151
/*
@@ -159,45 +171,65 @@ public boolean initialize() {
159171
return false;
160172
}
161173

162-
/* Read the classes and fields. */
163-
int fieldIndex = 0;
164-
for (int i = 0; i < classCount; i++) {
165-
int typeId = Pack200Coder.readUVAsInt(stream);
166-
167-
ClassInfo classInfo = getClassInfo(typeId);
168-
169-
int numInstanceFields = Pack200Coder.readUVAsInt(stream);
170-
classInfo.setInstanceFieldCount(numInstanceFields);
171-
172-
int numStaticFields = Pack200Coder.readUVAsInt(stream);
173-
classInfo.setStaticFieldCount(numStaticFields);
174-
175-
classInfo.setInstanceFields(fieldInfoTable.addressOf(fieldIndex));
176-
for (int j = 0; j < numInstanceFields; j++) {
177-
Pointer fieldInfo = (Pointer) fieldInfoTable.addressOf(fieldIndex);
178-
fieldInfo.writeWord(0, stream.getPosition());
179-
FieldInfoAccess.skipFieldInfo(stream);
180-
fieldIndex++;
174+
/*
175+
* Next write the metadata from all data arrays into the data structures.
176+
*/
177+
int fieldNameTableStartIdx = 0;
178+
for (HeapDumpEncodedData encodedData : encodedDataArray) {
179+
byte[] data = encodedData.data;
180+
181+
/* Re-initialize the stream. */
182+
Pointer start = NonmovableArrays.getArrayBase(NonmovableArrays.fromImageHeap(data));
183+
ByteStreamAccess.initialize(stream, start);
184+
185+
/* Re-read the header. */
186+
NativeCoder.readInt(stream); // field count
187+
int classCount = NativeCoder.readInt(stream);
188+
int currentFieldNameCount = NativeCoder.readInt(stream);
189+
Pack200Coder.readUVAsInt(stream); // maxTypeId
190+
191+
/* Read the classes and fields. */
192+
int fieldIndex = 0;
193+
for (int i = 0; i < classCount; i++) {
194+
int typeId = Pack200Coder.readUVAsInt(stream);
195+
196+
ClassInfo classInfo = getClassInfo(typeId);
197+
198+
int numInstanceFields = Pack200Coder.readUVAsInt(stream);
199+
classInfo.setInstanceFieldCount(numInstanceFields);
200+
201+
int numStaticFields = Pack200Coder.readUVAsInt(stream);
202+
classInfo.setStaticFieldCount(numStaticFields);
203+
204+
classInfo.setInstanceFields(fieldInfoTable.addressOf(fieldIndex));
205+
for (int j = 0; j < numInstanceFields; j++) {
206+
Pointer fieldInfo = (Pointer) fieldInfoTable.addressOf(fieldIndex);
207+
fieldInfo.writeWord(0, stream.getPosition());
208+
FieldInfoAccess.skipFieldInfo(stream);
209+
fieldIndex++;
210+
}
211+
212+
classInfo.setStaticFields(fieldInfoTable.addressOf(fieldIndex));
213+
for (int j = 0; j < numStaticFields; j++) {
214+
Pointer fieldInfo = (Pointer) fieldInfoTable.addressOf(fieldIndex);
215+
fieldInfo.writeWord(0, stream.getPosition());
216+
FieldInfoAccess.skipFieldInfo(stream);
217+
fieldIndex++;
218+
}
181219
}
182220

183-
classInfo.setStaticFields(fieldInfoTable.addressOf(fieldIndex));
184-
for (int j = 0; j < numStaticFields; j++) {
185-
Pointer fieldInfo = (Pointer) fieldInfoTable.addressOf(fieldIndex);
186-
fieldInfo.writeWord(0, stream.getPosition());
187-
FieldInfoAccess.skipFieldInfo(stream);
188-
fieldIndex++;
221+
/* Fill the symbol table. */
222+
for (int i = fieldNameTableStartIdx; i < currentFieldNameCount + fieldNameTableStartIdx; i++) {
223+
Pointer fieldName = (Pointer) fieldNameTable.addressOf(i);
224+
fieldName.writeWord(0, stream.getPosition());
225+
int length = Pack200Coder.readUVAsInt(stream);
226+
stream.setPosition(stream.getPosition().add(length));
189227
}
228+
fieldNameTableStartIdx += currentFieldNameCount;
229+
Pointer end = start.add(data.length);
230+
assert stream.getPosition().equal(end);
190231
}
191232

192-
/* Fill the symbol table. */
193-
for (int i = 0; i < fieldNameCount; i++) {
194-
Pointer fieldName = (Pointer) fieldNameTable.addressOf(i);
195-
fieldName.writeWord(0, stream.getPosition());
196-
int length = Pack200Coder.readUVAsInt(stream);
197-
stream.setPosition(stream.getPosition().add(length));
198-
}
199-
assert stream.getPosition().equal(end);
200-
201233
/* Store the DynamicHubs in their corresponding ClassInfo structs. */
202234
computeHubDataVisitor.initialize();
203235
Heap.getHeap().walkImageHeapObjects(computeHubDataVisitor);
@@ -290,6 +322,16 @@ static int computeFieldsDumpSize(FieldInfoPointer fields, int fieldCount) {
290322
return result;
291323
}
292324

325+
@Override
326+
public boolean accessibleInFutureLayers() {
327+
return true;
328+
}
329+
330+
@Override
331+
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
332+
return LayeredImageSingletonBuilderFlags.RUNTIME_ACCESS_ONLY;
333+
}
334+
293335
@RawStructure
294336
public interface ClassInfo extends PointerBase {
295337
@RawField
@@ -444,4 +486,26 @@ public void visitObject(Object o) {
444486
}
445487
}
446488
}
489+
490+
public static class HeapDumpEncodedData implements MultiLayeredImageSingleton, UnsavedSingleton {
491+
@UnknownObjectField(availability = AfterCompilation.class) private byte[] data;
492+
493+
@Override
494+
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
495+
return LayeredImageSingletonBuilderFlags.ALL_ACCESS;
496+
}
497+
498+
private static HeapDumpEncodedData currentLayer() {
499+
return LayeredImageSingletonSupport.singleton().lookup(HeapDumpEncodedData.class, false, true);
500+
}
501+
502+
private static HeapDumpEncodedData[] layeredSingletons() {
503+
return MultiLayeredImageSingleton.getAllLayers(HeapDumpEncodedData.class);
504+
}
505+
506+
@Platforms(Platform.HOSTED_ONLY.class)
507+
public static void setData(byte[] value) {
508+
HeapDumpEncodedData.currentLayer().data = value;
509+
}
510+
}
447511
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/dump/HeapDumpSupportImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ public class HeapDumpSupportImpl extends HeapDumping {
6666
private boolean outOfMemoryHeapDumpAttempted;
6767

6868
@Platforms(Platform.HOSTED_ONLY.class)
69-
public HeapDumpSupportImpl(HeapDumpMetadata metadata) {
70-
this.writer = new HeapDumpWriter(metadata);
69+
public HeapDumpSupportImpl() {
70+
this.writer = new HeapDumpWriter();
7171
this.heapDumpOperation = new HeapDumpOperation();
7272
}
7373

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/dump/HeapDumpWriter.java

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -407,16 +407,14 @@ public class HeapDumpWriter {
407407
private final DumpObjectsVisitor dumpObjectsVisitor = new DumpObjectsVisitor();
408408
private final CodeMetadataVisitor codeMetadataVisitor = new CodeMetadataVisitor();
409409
private final ThreadLocalsVisitor threadLocalsVisitor = new ThreadLocalsVisitor();
410-
private final HeapDumpMetadata metadata;
411410

412411
private BufferedFile f;
413412
private long topLevelRecordBegin = -1;
414413
private long subRecordBegin = -1;
415414
private boolean error;
416415

417416
@Platforms(Platform.HOSTED_ONLY.class)
418-
public HeapDumpWriter(HeapDumpMetadata metadata) {
419-
this.metadata = metadata;
417+
public HeapDumpWriter() {
420418
}
421419

422420
public boolean dumpHeap(RawFileDescriptor fd) {
@@ -454,11 +452,11 @@ private boolean initialize(RawFileDescriptor fd) {
454452
if (f.isNull()) {
455453
return false;
456454
}
457-
return metadata.initialize();
455+
return HeapDumpMetadata.singleton().initialize();
458456
}
459457

460458
private void teardown() {
461-
metadata.teardown();
459+
HeapDumpMetadata.singleton().teardown();
462460

463461
assert f.isNull() || error || file().getUnflushedDataSize(f) == 0;
464462
file().free(f);
@@ -547,8 +545,8 @@ private void endSubRecord(long recordSize) {
547545
}
548546

549547
private void writeClassNames() {
550-
for (int i = 0; i < metadata.getClassInfoCount(); i++) {
551-
ClassInfo classInfo = metadata.getClassInfo(i);
548+
for (int i = 0; i < HeapDumpMetadata.singleton().getClassInfoCount(); i++) {
549+
ClassInfo classInfo = HeapDumpMetadata.singleton().getClassInfo(i);
552550
if (ClassInfoAccess.isValid(classInfo)) {
553551
writeSymbol(classInfo.getHub().getName(), dotWithSlashReplacer);
554552
}
@@ -574,15 +572,15 @@ private void writeSymbol(FieldName fieldName) {
574572
}
575573

576574
private void writeFieldNames() {
577-
for (int i = 0; i < metadata.getFieldNameCount(); i++) {
578-
FieldName fieldName = metadata.getFieldName(i);
575+
for (int i = 0; i < HeapDumpMetadata.singleton().getFieldNameCount(); i++) {
576+
FieldName fieldName = HeapDumpMetadata.singleton().getFieldName(i);
579577
writeSymbol(fieldName);
580578
}
581579
}
582580

583581
private void writeLoadedClasses() {
584-
for (int i = 0; i < metadata.getClassInfoCount(); i++) {
585-
ClassInfo classInfo = metadata.getClassInfo(i);
582+
for (int i = 0; i < HeapDumpMetadata.singleton().getClassInfoCount(); i++) {
583+
ClassInfo classInfo = HeapDumpMetadata.singleton().getClassInfo(i);
586584
if (ClassInfoAccess.isValid(classInfo)) {
587585
DynamicHub hub = classInfo.getHub();
588586
if (hub.isLoaded()) {
@@ -642,8 +640,8 @@ private void writeDummyStackTrace() {
642640
}
643641

644642
private void writeClasses() {
645-
for (int i = 0; i < metadata.getClassInfoCount(); i++) {
646-
ClassInfo classInfo = metadata.getClassInfo(i);
643+
for (int i = 0; i < HeapDumpMetadata.singleton().getClassInfoCount(); i++) {
644+
ClassInfo classInfo = HeapDumpMetadata.singleton().getClassInfo(i);
647645
if (ClassInfoAccess.isValid(classInfo)) {
648646
if (classInfo.getHub().isLoaded()) {
649647
writeClassDumpRecord(classInfo);
@@ -756,8 +754,8 @@ private void writeJNIGlobals() {
756754
}
757755

758756
private void writeStickyClasses() {
759-
for (int i = 0; i < metadata.getClassInfoCount(); i++) {
760-
ClassInfo classInfo = metadata.getClassInfo(i);
757+
for (int i = 0; i < HeapDumpMetadata.singleton().getClassInfoCount(); i++) {
758+
ClassInfo classInfo = HeapDumpMetadata.singleton().getClassInfo(i);
761759
if (ClassInfoAccess.isValid(classInfo)) {
762760
int recordSize = 1 + wordSize();
763761
startSubRecord(HProfSubRecord.GC_ROOT_STICKY_CLASS, recordSize);
@@ -879,7 +877,7 @@ private void markAsJniGlobalGCRoot(Object obj) {
879877
}
880878

881879
private void writeInstance(Object obj) {
882-
ClassInfo classInfo = metadata.getClassInfo(obj.getClass());
880+
ClassInfo classInfo = HeapDumpMetadata.singleton().getClassInfo(obj.getClass());
883881
int instanceFieldsSize = classInfo.getInstanceFieldsDumpSize();
884882
int recordSize = 1 + wordSize() + 4 + wordSize() + 4 + instanceFieldsSize;
885883

@@ -897,7 +895,7 @@ private void writeInstance(Object obj) {
897895
FieldInfo field = instanceFields.addressOf(i).read();
898896
writeFieldData(obj, field);
899897
}
900-
classInfo = metadata.getClassInfo(classInfo.getHub().getSuperHub());
898+
classInfo = HeapDumpMetadata.singleton().getClassInfo(classInfo.getHub().getSuperHub());
901899
} while (classInfo.isNonNull());
902900

903901
endSubRecord(recordSize);
@@ -1299,7 +1297,7 @@ private void visitFrame(FrameInfoQueryResult frame) {
12991297

13001298
/* Write the FRAME record. */
13011299
Class<?> sourceClass = getSourceClass(frame);
1302-
ClassInfo classInfo = metadata.getClassInfo(sourceClass);
1300+
ClassInfo classInfo = HeapDumpMetadata.singleton().getClassInfo(sourceClass);
13031301
int lineNumber = getLineNumber(frame);
13041302
writeFrame(classInfo.getSerialNum(), lineNumber, methodName, methodSignature, sourceFileName);
13051303
}
@@ -1398,7 +1396,7 @@ private UnsignedWord getObjectSize(Object obj) {
13981396
int length = ArrayLengthNode.arrayLength(obj);
13991397
return Word.unsigned(length).multiply(elementSize);
14001398
} else {
1401-
ClassInfo classInfo = metadata.getClassInfo(obj.getClass());
1399+
ClassInfo classInfo = HeapDumpMetadata.singleton().getClassInfo(obj.getClass());
14021400
return Word.unsigned(classInfo.getInstanceFieldsDumpSize());
14031401
}
14041402
}

0 commit comments

Comments
 (0)