Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
*/
package com.oracle.svm.core.heap.dump;

import java.util.EnumSet;

import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
Expand All @@ -44,14 +46,18 @@
import com.oracle.svm.core.heap.ObjectVisitor;
import com.oracle.svm.core.heap.UnknownObjectField;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.layeredimagesingleton.InitialLayerOnlyImageSingleton;
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonSupport;
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton;
import com.oracle.svm.core.memory.NullableNativeMemory;
import com.oracle.svm.core.nmt.NmtCategory;
import com.oracle.svm.core.util.coder.ByteStream;
import com.oracle.svm.core.util.coder.ByteStreamAccess;
import com.oracle.svm.core.util.coder.NativeCoder;
import com.oracle.svm.core.util.coder.Pack200Coder;

import jdk.graal.compiler.api.replacements.Fold;
import jdk.graal.compiler.word.Word;

/**
Expand Down Expand Up @@ -95,9 +101,8 @@
* |----------------------------|
* </pre>
*/
public class HeapDumpMetadata {
public class HeapDumpMetadata implements InitialLayerOnlyImageSingleton {
private final ComputeHubDataVisitor computeHubDataVisitor;
@UnknownObjectField(availability = AfterCompilation.class) private byte[] data;

private int fieldNameCount;
private int classInfoCount;
Expand All @@ -110,30 +115,37 @@ public HeapDumpMetadata() {
computeHubDataVisitor = new ComputeHubDataVisitor();
}

@Fold
public static HeapDumpMetadata singleton() {
return ImageSingletons.lookup(HeapDumpMetadata.class);
}

@Platforms(Platform.HOSTED_ONLY.class)
public void setData(byte[] value) {
this.data = value;
}

public boolean initialize() {
assert classInfos.isNull() && fieldInfoTable.isNull() && fieldNameTable.isNull();

Pointer start = NonmovableArrays.getArrayBase(NonmovableArrays.fromImageHeap(data));
Pointer end = start.add(data.length);
HeapDumpEncodedData[] encodedDataArray = HeapDumpEncodedData.layeredSingletons();

ByteStream stream = StackValue.get(ByteStream.class);
ByteStreamAccess.initialize(stream, start);

/* Read the header. */
int totalFieldCount = NativeCoder.readInt(stream);
int classCount = NativeCoder.readInt(stream);
fieldNameCount = NativeCoder.readInt(stream);
int maxTypeId = Pack200Coder.readUVAsInt(stream);
int totalFieldCount = 0;
int totalFieldNameCount = 0;
int maxTypeId = Integer.MIN_VALUE;

/*
* First read all encoded data arrays to determine how large of data structures to allocate.
*/
for (HeapDumpEncodedData encodedData : encodedDataArray) {
byte[] data = encodedData.data;

Pointer start = NonmovableArrays.getArrayBase(NonmovableArrays.fromImageHeap(data));
ByteStreamAccess.initialize(stream, start);

/* Read the header. */
totalFieldCount += NativeCoder.readInt(stream);
NativeCoder.readInt(stream); // class count
totalFieldNameCount += NativeCoder.readInt(stream);
maxTypeId = Integer.max(Pack200Coder.readUVAsInt(stream), maxTypeId);
}
fieldNameCount = totalFieldNameCount;
classInfoCount = maxTypeId + 1;

/*
Expand All @@ -159,45 +171,65 @@ public boolean initialize() {
return false;
}

/* Read the classes and fields. */
int fieldIndex = 0;
for (int i = 0; i < classCount; i++) {
int typeId = Pack200Coder.readUVAsInt(stream);

ClassInfo classInfo = getClassInfo(typeId);

int numInstanceFields = Pack200Coder.readUVAsInt(stream);
classInfo.setInstanceFieldCount(numInstanceFields);

int numStaticFields = Pack200Coder.readUVAsInt(stream);
classInfo.setStaticFieldCount(numStaticFields);

classInfo.setInstanceFields(fieldInfoTable.addressOf(fieldIndex));
for (int j = 0; j < numInstanceFields; j++) {
Pointer fieldInfo = (Pointer) fieldInfoTable.addressOf(fieldIndex);
fieldInfo.writeWord(0, stream.getPosition());
FieldInfoAccess.skipFieldInfo(stream);
fieldIndex++;
/*
* Next write the metadata from all data arrays into the data structures.
*/
int fieldNameTableStartIdx = 0;
for (HeapDumpEncodedData encodedData : encodedDataArray) {
byte[] data = encodedData.data;

/* Re-initialize the stream. */
Pointer start = NonmovableArrays.getArrayBase(NonmovableArrays.fromImageHeap(data));
ByteStreamAccess.initialize(stream, start);

/* Re-read the header. */
NativeCoder.readInt(stream); // field count
int classCount = NativeCoder.readInt(stream);
int currentFieldNameCount = NativeCoder.readInt(stream);
Pack200Coder.readUVAsInt(stream); // maxTypeId

/* Read the classes and fields. */
int fieldIndex = 0;
for (int i = 0; i < classCount; i++) {
int typeId = Pack200Coder.readUVAsInt(stream);

ClassInfo classInfo = getClassInfo(typeId);

int numInstanceFields = Pack200Coder.readUVAsInt(stream);
classInfo.setInstanceFieldCount(numInstanceFields);

int numStaticFields = Pack200Coder.readUVAsInt(stream);
classInfo.setStaticFieldCount(numStaticFields);

classInfo.setInstanceFields(fieldInfoTable.addressOf(fieldIndex));
for (int j = 0; j < numInstanceFields; j++) {
Pointer fieldInfo = (Pointer) fieldInfoTable.addressOf(fieldIndex);
fieldInfo.writeWord(0, stream.getPosition());
FieldInfoAccess.skipFieldInfo(stream);
fieldIndex++;
}

classInfo.setStaticFields(fieldInfoTable.addressOf(fieldIndex));
for (int j = 0; j < numStaticFields; j++) {
Pointer fieldInfo = (Pointer) fieldInfoTable.addressOf(fieldIndex);
fieldInfo.writeWord(0, stream.getPosition());
FieldInfoAccess.skipFieldInfo(stream);
fieldIndex++;
}
}

classInfo.setStaticFields(fieldInfoTable.addressOf(fieldIndex));
for (int j = 0; j < numStaticFields; j++) {
Pointer fieldInfo = (Pointer) fieldInfoTable.addressOf(fieldIndex);
fieldInfo.writeWord(0, stream.getPosition());
FieldInfoAccess.skipFieldInfo(stream);
fieldIndex++;
/* Fill the symbol table. */
for (int i = fieldNameTableStartIdx; i < currentFieldNameCount + fieldNameTableStartIdx; i++) {
Pointer fieldName = (Pointer) fieldNameTable.addressOf(i);
fieldName.writeWord(0, stream.getPosition());
int length = Pack200Coder.readUVAsInt(stream);
stream.setPosition(stream.getPosition().add(length));
}
fieldNameTableStartIdx += currentFieldNameCount;
Pointer end = start.add(data.length);
assert stream.getPosition().equal(end);
}

/* Fill the symbol table. */
for (int i = 0; i < fieldNameCount; i++) {
Pointer fieldName = (Pointer) fieldNameTable.addressOf(i);
fieldName.writeWord(0, stream.getPosition());
int length = Pack200Coder.readUVAsInt(stream);
stream.setPosition(stream.getPosition().add(length));
}
assert stream.getPosition().equal(end);

/* Store the DynamicHubs in their corresponding ClassInfo structs. */
computeHubDataVisitor.initialize();
Heap.getHeap().walkImageHeapObjects(computeHubDataVisitor);
Expand Down Expand Up @@ -290,6 +322,16 @@ static int computeFieldsDumpSize(FieldInfoPointer fields, int fieldCount) {
return result;
}

@Override
public boolean accessibleInFutureLayers() {
return true;
}

@Override
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
return LayeredImageSingletonBuilderFlags.RUNTIME_ACCESS_ONLY;
}

@RawStructure
public interface ClassInfo extends PointerBase {
@RawField
Expand Down Expand Up @@ -444,4 +486,26 @@ public void visitObject(Object o) {
}
}
}

public static class HeapDumpEncodedData implements MultiLayeredImageSingleton, UnsavedSingleton {
@UnknownObjectField(availability = AfterCompilation.class) private byte[] data;

@Override
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
return LayeredImageSingletonBuilderFlags.ALL_ACCESS;
}

private static HeapDumpEncodedData currentLayer() {
return LayeredImageSingletonSupport.singleton().lookup(HeapDumpEncodedData.class, false, true);
}

private static HeapDumpEncodedData[] layeredSingletons() {
return MultiLayeredImageSingleton.getAllLayers(HeapDumpEncodedData.class);
}

@Platforms(Platform.HOSTED_ONLY.class)
public static void setData(byte[] value) {
HeapDumpEncodedData.currentLayer().data = value;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ public class HeapDumpSupportImpl extends HeapDumping {
private boolean outOfMemoryHeapDumpAttempted;

@Platforms(Platform.HOSTED_ONLY.class)
public HeapDumpSupportImpl(HeapDumpMetadata metadata) {
this.writer = new HeapDumpWriter(metadata);
public HeapDumpSupportImpl() {
this.writer = new HeapDumpWriter();
this.heapDumpOperation = new HeapDumpOperation();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -407,16 +407,14 @@ public class HeapDumpWriter {
private final DumpObjectsVisitor dumpObjectsVisitor = new DumpObjectsVisitor();
private final CodeMetadataVisitor codeMetadataVisitor = new CodeMetadataVisitor();
private final ThreadLocalsVisitor threadLocalsVisitor = new ThreadLocalsVisitor();
private final HeapDumpMetadata metadata;

private BufferedFile f;
private long topLevelRecordBegin = -1;
private long subRecordBegin = -1;
private boolean error;

@Platforms(Platform.HOSTED_ONLY.class)
public HeapDumpWriter(HeapDumpMetadata metadata) {
this.metadata = metadata;
public HeapDumpWriter() {
}

public boolean dumpHeap(RawFileDescriptor fd) {
Expand Down Expand Up @@ -454,11 +452,11 @@ private boolean initialize(RawFileDescriptor fd) {
if (f.isNull()) {
return false;
}
return metadata.initialize();
return HeapDumpMetadata.singleton().initialize();
}

private void teardown() {
metadata.teardown();
HeapDumpMetadata.singleton().teardown();

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

private void writeClassNames() {
for (int i = 0; i < metadata.getClassInfoCount(); i++) {
ClassInfo classInfo = metadata.getClassInfo(i);
for (int i = 0; i < HeapDumpMetadata.singleton().getClassInfoCount(); i++) {
ClassInfo classInfo = HeapDumpMetadata.singleton().getClassInfo(i);
if (ClassInfoAccess.isValid(classInfo)) {
writeSymbol(classInfo.getHub().getName(), dotWithSlashReplacer);
}
Expand All @@ -574,15 +572,15 @@ private void writeSymbol(FieldName fieldName) {
}

private void writeFieldNames() {
for (int i = 0; i < metadata.getFieldNameCount(); i++) {
FieldName fieldName = metadata.getFieldName(i);
for (int i = 0; i < HeapDumpMetadata.singleton().getFieldNameCount(); i++) {
FieldName fieldName = HeapDumpMetadata.singleton().getFieldName(i);
writeSymbol(fieldName);
}
}

private void writeLoadedClasses() {
for (int i = 0; i < metadata.getClassInfoCount(); i++) {
ClassInfo classInfo = metadata.getClassInfo(i);
for (int i = 0; i < HeapDumpMetadata.singleton().getClassInfoCount(); i++) {
ClassInfo classInfo = HeapDumpMetadata.singleton().getClassInfo(i);
if (ClassInfoAccess.isValid(classInfo)) {
DynamicHub hub = classInfo.getHub();
if (hub.isLoaded()) {
Expand Down Expand Up @@ -642,8 +640,8 @@ private void writeDummyStackTrace() {
}

private void writeClasses() {
for (int i = 0; i < metadata.getClassInfoCount(); i++) {
ClassInfo classInfo = metadata.getClassInfo(i);
for (int i = 0; i < HeapDumpMetadata.singleton().getClassInfoCount(); i++) {
ClassInfo classInfo = HeapDumpMetadata.singleton().getClassInfo(i);
if (ClassInfoAccess.isValid(classInfo)) {
if (classInfo.getHub().isLoaded()) {
writeClassDumpRecord(classInfo);
Expand Down Expand Up @@ -756,8 +754,8 @@ private void writeJNIGlobals() {
}

private void writeStickyClasses() {
for (int i = 0; i < metadata.getClassInfoCount(); i++) {
ClassInfo classInfo = metadata.getClassInfo(i);
for (int i = 0; i < HeapDumpMetadata.singleton().getClassInfoCount(); i++) {
ClassInfo classInfo = HeapDumpMetadata.singleton().getClassInfo(i);
if (ClassInfoAccess.isValid(classInfo)) {
int recordSize = 1 + wordSize();
startSubRecord(HProfSubRecord.GC_ROOT_STICKY_CLASS, recordSize);
Expand Down Expand Up @@ -879,7 +877,7 @@ private void markAsJniGlobalGCRoot(Object obj) {
}

private void writeInstance(Object obj) {
ClassInfo classInfo = metadata.getClassInfo(obj.getClass());
ClassInfo classInfo = HeapDumpMetadata.singleton().getClassInfo(obj.getClass());
int instanceFieldsSize = classInfo.getInstanceFieldsDumpSize();
int recordSize = 1 + wordSize() + 4 + wordSize() + 4 + instanceFieldsSize;

Expand All @@ -897,7 +895,7 @@ private void writeInstance(Object obj) {
FieldInfo field = instanceFields.addressOf(i).read();
writeFieldData(obj, field);
}
classInfo = metadata.getClassInfo(classInfo.getHub().getSuperHub());
classInfo = HeapDumpMetadata.singleton().getClassInfo(classInfo.getHub().getSuperHub());
} while (classInfo.isNonNull());

endSubRecord(recordSize);
Expand Down Expand Up @@ -1299,7 +1297,7 @@ private void visitFrame(FrameInfoQueryResult frame) {

/* Write the FRAME record. */
Class<?> sourceClass = getSourceClass(frame);
ClassInfo classInfo = metadata.getClassInfo(sourceClass);
ClassInfo classInfo = HeapDumpMetadata.singleton().getClassInfo(sourceClass);
int lineNumber = getLineNumber(frame);
writeFrame(classInfo.getSerialNum(), lineNumber, methodName, methodSignature, sourceFileName);
}
Expand Down Expand Up @@ -1398,7 +1396,7 @@ private UnsignedWord getObjectSize(Object obj) {
int length = ArrayLengthNode.arrayLength(obj);
return Word.unsigned(length).multiply(elementSize);
} else {
ClassInfo classInfo = metadata.getClassInfo(obj.getClass());
ClassInfo classInfo = HeapDumpMetadata.singleton().getClassInfo(obj.getClass());
return Word.unsigned(classInfo.getInstanceFieldsDumpSize());
}
}
Expand Down
Loading