From 7e95e935d1eca5e793bdbd8341e09f28e0fd34f5 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 23 Nov 2022 22:04:26 +0100 Subject: [PATCH] Wasm: write more info about classes in DWARF --- .../backend/wasm/dwarf/DwarfConstants.java | 3 + .../backend/wasm/dwarf/DwarfInfoWriter.java | 2 + .../wasm/generate/DwarfClassGenerator.java | 63 ++++++++++++++++++- .../wasm/generate/DwarfFunctionGenerator.java | 5 ++ .../wasm/generate/WasmClassGenerator.java | 18 ++++-- 5 files changed, 86 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/teavm/backend/wasm/dwarf/DwarfConstants.java b/core/src/main/java/org/teavm/backend/wasm/dwarf/DwarfConstants.java index 8f100efb3..10d82d7da 100644 --- a/core/src/main/java/org/teavm/backend/wasm/dwarf/DwarfConstants.java +++ b/core/src/main/java/org/teavm/backend/wasm/dwarf/DwarfConstants.java @@ -24,6 +24,7 @@ public final class DwarfConstants { public static final int DW_TAG_FORMAL_PARAMETER = 0x05; public static final int DW_TAG_POINTER_TYPE = 0x0F; public static final int DW_TAG_COMPILE_UNIT = 0x11; + public static final int DW_TAG_INHERITANCE = 0x1C; public static final int DW_TAG_BASE_TYPE = 0x24; public static final int DW_TAG_SUBPROGRAM = 0x2E; public static final int DW_TAG_VARIABLE = 0x34; @@ -72,6 +73,8 @@ public final class DwarfConstants { public static final int DW_FORM_FLAG_PRESENT = 0x19; public static final int DW_FORM_LINE_STRP = 0x1F; + public static final int DW_OP_ADDR = 0x03; + public static final int DW_OP_STACK_VALUE = 0x9F; public static final int DW_OP_WASM_LOCATION = 0xED; public static final int DW_LNS_COPY = 0x01; diff --git a/core/src/main/java/org/teavm/backend/wasm/dwarf/DwarfInfoWriter.java b/core/src/main/java/org/teavm/backend/wasm/dwarf/DwarfInfoWriter.java index fdec3a46d..05ed5c840 100644 --- a/core/src/main/java/org/teavm/backend/wasm/dwarf/DwarfInfoWriter.java +++ b/core/src/main/java/org/teavm/backend/wasm/dwarf/DwarfInfoWriter.java @@ -20,6 +20,7 @@ import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_CHILDREN_YES; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Objects; import java.util.function.Consumer; import org.teavm.backend.wasm.dwarf.blob.BinaryDataConsumer; import org.teavm.backend.wasm.dwarf.blob.Blob; @@ -115,6 +116,7 @@ public class DwarfInfoWriter { } public DwarfInfoWriter mark(DwarfPlaceholder placeholder) { + Objects.requireNonNull(placeholder); placements.add(new Placement(output.ptr()) { @Override void write(Blob blob) { diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/DwarfClassGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/DwarfClassGenerator.java index 4d5bdcf9e..4b98bbe40 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/DwarfClassGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/DwarfClassGenerator.java @@ -22,18 +22,25 @@ import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_ATE_UTF; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_BYTE_SIZE; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_DECLARATION; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_ENCODING; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_LOCATION; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_NAME; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_TYPE; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_FORM_DATA1; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_FORM_DATA2; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_FORM_EXPRLOC; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_FORM_FLAG_PRESENT; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_FORM_REF4; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_FORM_STRP; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_OP_ADDR; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_OP_STACK_VALUE; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_BASE_TYPE; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_CLASS_TYPE; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_INHERITANCE; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_NAMESPACE; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_POINTER_TYPE; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_SUBPROGRAM; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_UNSPECIFIED_TYPE; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_VARIABLE; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; @@ -57,12 +64,15 @@ public class DwarfClassGenerator { private final DwarfStrings strings; private DwarfAbbreviation nsAbbrev; private DwarfAbbreviation classTypeAbbrev; + private DwarfAbbreviation inheritanceAbbrev; private DwarfAbbreviation methodAbbrev; private DwarfPlaceholder[] primitiveTypes = new DwarfPlaceholder[PrimitiveType.values().length]; private DwarfPlaceholder unspecifiedType; private DwarfAbbreviation baseTypeAbbrev; private DwarfAbbreviation pointerAbbrev; + private DwarfAbbreviation variableAbbrev; private List postponedWrites = new ArrayList<>(); + private ClassType classClass; public DwarfClassGenerator(DwarfInfoWriter writer, DwarfStrings strings) { this.writer = writer; @@ -99,10 +109,12 @@ public class DwarfClassGenerator { } public void write() { + classClass = getClass("java.lang.Class"); root.writeChildren(); for (var subprogram : rootSubprograms) { subprogram.write(); } + flushTypes(); } private DwarfAbbreviation getMethodAbbrev() { @@ -128,11 +140,21 @@ public class DwarfClassGenerator { if (classTypeAbbrev == null) { classTypeAbbrev = writer.abbreviation(DW_TAG_CLASS_TYPE, true, data -> { data.writeLEB(DW_AT_NAME).writeLEB(DW_FORM_STRP); + data.writeLEB(DW_AT_BYTE_SIZE).writeLEB(DW_FORM_DATA2); }); } return classTypeAbbrev; } + private DwarfAbbreviation getInheritanceAbbrev() { + if (inheritanceAbbrev == null) { + inheritanceAbbrev = writer.abbreviation(DW_TAG_INHERITANCE, false, data -> { + data.writeLEB(DW_AT_TYPE).writeLEB(DW_FORM_REF4); + }); + } + return inheritanceAbbrev; + } + public DwarfPlaceholder getTypePtr(VariableType type) { switch (type) { case INT: @@ -169,7 +191,7 @@ public class DwarfClassGenerator { } private DwarfPlaceholder getClassType(String name) { - return getClass(name).getPointerPtr(); + return getClass(name).ptr; } private DwarfPlaceholder getPrimitivePtr(ValueType.Primitive type) { @@ -256,6 +278,17 @@ public class DwarfClassGenerator { return pointerAbbrev; } + private DwarfAbbreviation getVariableAbbrev() { + if (variableAbbrev == null) { + variableAbbrev = writer.abbreviation(DW_TAG_VARIABLE, false, blob -> { + blob.writeLEB(DW_AT_NAME).writeLEB(DW_FORM_STRP); + blob.writeLEB(DW_AT_TYPE).writeLEB(DW_FORM_REF4); + blob.writeLEB(DW_AT_LOCATION).writeLEB(DW_FORM_EXPRLOC); + }); + } + return variableAbbrev; + } + public class Namespace { public final String name; final Map namespaces = new LinkedHashMap<>(); @@ -295,16 +328,31 @@ public class DwarfClassGenerator { final DwarfPlaceholder ptr; private DwarfPlaceholder pointerPtr; final Map subprograms = new LinkedHashMap<>(); + private ClassType superclass; + private int size; + private int pointer = -1; private ClassType(String name) { ptr = writer.placeholder(4); this.name = name; } + public void setSuperclass(ClassType superclass) { + this.superclass = superclass; + } + public Subprogram getSubprogram(MethodDescriptor desc) { return subprograms.computeIfAbsent(desc, d -> new Subprogram(d.getName(), desc)); } + public void setSize(int size) { + this.size = size; + } + + public void setPointer(int pointer) { + this.pointer = pointer; + } + public DwarfPlaceholder getPointerPtr() { if (pointerPtr == null) { pointerPtr = writer.placeholder(4); @@ -315,6 +363,10 @@ public class DwarfClassGenerator { private void write() { writer.mark(ptr).tag(getClassTypeAbbrev()); writer.writeInt(strings.stringRef(name)); + writer.writeShort(size); + if (superclass != null) { + writer.tag(getInheritanceAbbrev()).ref(superclass.ptr, Blob::writeInt); + } for (var child : subprograms.values()) { child.write(); } @@ -322,6 +374,15 @@ public class DwarfClassGenerator { writer.mark(pointerPtr).tag(getPointerAbbrev()); writer.ref(ptr, Blob::writeInt); } + if (pointer >= 0) { + writer.tag(getVariableAbbrev()); + writer.writeInt(strings.stringRef("__class__")); + writer.ref(classClass.ptr, Blob::writeInt); + var ops = new Blob(); + ops.writeByte(DW_OP_ADDR).writeInt(pointer).writeByte(DW_OP_STACK_VALUE); + writer.writeLEB(ops.size()); + ops.newReader(writer::write).readRemaining(); + } writer.emptyTag(); } } diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/DwarfFunctionGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/DwarfFunctionGenerator.java index 965f714a4..d99b117b7 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/DwarfFunctionGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/DwarfFunctionGenerator.java @@ -25,6 +25,7 @@ import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_FORM_ADDR; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_FORM_EXPRLOC; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_FORM_REF4; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_FORM_STRP; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_OP_STACK_VALUE; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_OP_WASM_LOCATION; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_FORMAL_PARAMETER; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_SUBPROGRAM; @@ -33,6 +34,7 @@ import org.teavm.backend.wasm.dwarf.DwarfAbbreviation; import org.teavm.backend.wasm.dwarf.blob.Blob; import org.teavm.backend.wasm.dwarf.blob.Marker; import org.teavm.backend.wasm.model.WasmFunction; +import org.teavm.model.util.VariableType; public class DwarfFunctionGenerator { private DwarfClassGenerator classGen; @@ -114,6 +116,9 @@ public class DwarfFunctionGenerator { var operations = new Blob(); operations.writeByte(DW_OP_WASM_LOCATION).writeByte(0).writeLEB(i + 1); + if (local.getJavaType() == VariableType.OBJECT) { + operations.writeByte(DW_OP_STACK_VALUE); + } writer.writeLEB(operations.size()); operations.newReader(writer::write).readRemaining(); } diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java index fe7b4c24a..3944fb30b 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java @@ -179,12 +179,22 @@ public class WasmClassGenerator { var cls = classSource.get(className); if (cls != null) { - calculateLayout(cls, binaryData); + DwarfClassGenerator.ClassType dwarfClass; + if (dwarfClassGenerator != null) { + dwarfClass = dwarfClassGenerator.getClass(className); + dwarfClass.setSuperclass(cls.getParent() != null + ? dwarfClassGenerator.getClass(cls.getParent()) + : null); + } else { + dwarfClass = null; + } + calculateLayout(cls, binaryData, dwarfClass); if (binaryData.start >= 0) { binaryData.start = binaryWriter.append(createStructure(binaryData)); } - if (dwarfClassGenerator != null) { - dwarfClassGenerator.getClass(className); + if (dwarfClass != null) { + dwarfClass.setSize(binaryData.size); + dwarfClass.setPointer(binaryData.start); } } } else if (type instanceof ValueType.Array) { @@ -486,7 +496,7 @@ public class WasmClassGenerator { return binaryDataMap.get(type).function; } - private void calculateLayout(ClassReader cls, ClassBinaryData data) { + private void calculateLayout(ClassReader cls, ClassBinaryData data, DwarfClassGenerator.ClassType dwarfClass) { if (cls.getName().equals(Structure.class.getName()) || cls.getName().equals(Address.class.getName())) { data.size = 0; data.start = -1;