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 21bb8d131..ab9a6f288 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 @@ -22,6 +22,7 @@ public final class DwarfConstants { public static final int DW_TAG_CLASS_TYPE = 0x02; public static final int DW_TAG_FORMAL_PARAMETER = 0x05; + public static final int DW_TAG_MEMBER = 0x0d; 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; @@ -38,7 +39,11 @@ public final class DwarfConstants { public static final int DW_AT_LOW_PC = 0x11; public static final int DW_AT_HIGH_PC = 0x12; public static final int DW_AT_LANGUAGE = 0x13; + public static final int DW_AT_CONTAINING_TYPE = 0x1D; public static final int DW_AT_PRODUCER = 0x25; + public static final int DW_AT_ACCESSIBILITY = 0x32; + public static final int DW_AT_CALLING_CONVENTION = 0x36; + public static final int DW_AT_DATA_MEMBER_LOCATION = 0x38; public static final int DW_AT_DECLARATION = 0x3C; public static final int DW_AT_ENCODING = 0x3E; public static final int DW_AT_SPECIFICATION = 0x47; @@ -75,6 +80,10 @@ public final class DwarfConstants { public static final int DW_FORM_LINE_STRP = 0x1F; public static final int DW_OP_ADDR = 0x03; + public static final int DW_OP_DEREF = 0x06; + public static final int DW_OP_SHL = 0x24; + public static final int DW_OP_LIT0 = 0x30; + public static final int DW_OP_LIT3 = 0x33; public static final int DW_OP_STACK_VALUE = 0x9F; public static final int DW_OP_WASM_LOCATION = 0xED; @@ -93,6 +102,10 @@ public final class DwarfConstants { public static final int DW_LNE_END_SEQUENCE = 0x01; + public static final int DW_ACCESS_PUBLIC = 0x01; + + public static final int DW_CC_PASS_BY_REFERENCE = 0x04; + private DwarfConstants() { } } 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 a1bf68348..3f50ae04c 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 @@ -15,25 +15,34 @@ */ package org.teavm.backend.wasm.generate; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_ACCESS_PUBLIC; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_ATE_BOOLEAN; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_ATE_FLOAT; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_ATE_SIGNED; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_ATE_UTF; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_ACCESSIBILITY; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_BYTE_SIZE; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_CALLING_CONVENTION; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_CONTAINING_TYPE; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_DATA_MEMBER_LOCATION; 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_CC_PASS_BY_REFERENCE; 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_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_OP_DEREF; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_OP_LIT3; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_OP_SHL; 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_MEMBER; 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_UNSPECIFIED_TYPE; @@ -63,6 +72,8 @@ public class DwarfClassGenerator { private DwarfAbbreviation nsAbbrev; private DwarfAbbreviation classTypeAbbrev; private DwarfAbbreviation inheritanceAbbrev; + private DwarfAbbreviation immutableMemberAbbrev; + private DwarfAbbreviation memberAbbrev; private DwarfPlaceholder[] primitiveTypes = new DwarfPlaceholder[PrimitiveType.values().length]; private DwarfPlaceholder unspecifiedType; private DwarfAbbreviation baseTypeAbbrev; @@ -96,7 +107,11 @@ public class DwarfClassGenerator { ns = ns.getNamespace(fullName.substring(index, next)); index = next + 1; } - return ns.getClass(fullName.substring(index)); + var cls = ns.getClass(fullName.substring(index)); + if (fullName.equals("java.lang.Object")) { + cls.isRoot = true; + } + return cls; } public void registerSubprogram(String functionName, Subprogram subprogram) { @@ -129,7 +144,9 @@ 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_CONTAINING_TYPE).writeLEB(DW_FORM_REF4); data.writeLEB(DW_AT_BYTE_SIZE).writeLEB(DW_FORM_DATA2); + data.writeLEB(DW_AT_CALLING_CONVENTION).writeLEB(DW_FORM_DATA1); }); } return classTypeAbbrev; @@ -144,6 +161,30 @@ public class DwarfClassGenerator { return inheritanceAbbrev; } + private DwarfAbbreviation getImmutableMemberAbbrev() { + if (immutableMemberAbbrev == null) { + immutableMemberAbbrev = writer.abbreviation(DW_TAG_MEMBER, false, data -> { + data.writeLEB(DW_AT_NAME).writeLEB(DW_FORM_STRP); + data.writeLEB(DW_AT_TYPE).writeLEB(DW_FORM_REF4); + data.writeLEB(DW_AT_DATA_MEMBER_LOCATION).writeLEB(DW_FORM_EXPRLOC); + data.writeLEB(DW_AT_ACCESSIBILITY).writeLEB(DW_FORM_DATA1); + }); + } + return immutableMemberAbbrev; + } + + private DwarfAbbreviation getMemberAbbrev() { + if (memberAbbrev == null) { + memberAbbrev = writer.abbreviation(DW_TAG_MEMBER, false, data -> { + data.writeLEB(DW_AT_NAME).writeLEB(DW_FORM_STRP); + data.writeLEB(DW_AT_TYPE).writeLEB(DW_FORM_REF4); + data.writeLEB(DW_AT_DATA_MEMBER_LOCATION).writeLEB(DW_FORM_DATA2); + data.writeLEB(DW_AT_ACCESSIBILITY).writeLEB(DW_FORM_DATA1); + }); + } + return memberAbbrev; + } + public DwarfPlaceholder getTypePtr(VariableType type) { switch (type) { case INT: @@ -180,7 +221,7 @@ public class DwarfClassGenerator { } private DwarfPlaceholder getClassType(String name) { - return getClass(name).ptr; + return getClass(name).getPointerPtr(); } private DwarfPlaceholder getPrimitivePtr(ValueType.Primitive type) { @@ -314,9 +355,11 @@ public class DwarfClassGenerator { public class ClassType { public final String name; + boolean isRoot; final DwarfPlaceholder ptr; private DwarfPlaceholder pointerPtr; final Map subprograms = new LinkedHashMap<>(); + List fields; private ClassType superclass; private int size; private int pointer = -1; @@ -342,6 +385,21 @@ public class DwarfClassGenerator { this.pointer = pointer; } + public void registerField(String name, ValueType type, int offset) { + addField(new InstanceField(name, type, offset)); + } + + public void registerStaticField(String name, ValueType type, int address) { + addField(new StaticField(name, type, address)); + } + + private void addField(Field field) { + if (fields == null) { + fields = new ArrayList<>(); + } + fields.add(field); + } + public DwarfPlaceholder getPointerPtr() { if (pointerPtr == null) { pointerPtr = writer.placeholder(4); @@ -352,7 +410,9 @@ public class DwarfClassGenerator { private void write() { writer.mark(ptr).tag(getClassTypeAbbrev()); writer.writeInt(strings.stringRef(name)); + writer.ref(ptr, Blob::writeInt); writer.writeShort(size); + writer.writeByte(DW_CC_PASS_BY_REFERENCE); if (superclass != null) { writer.tag(getInheritanceAbbrev()).ref(superclass.ptr, Blob::writeInt); } @@ -365,15 +425,38 @@ public class DwarfClassGenerator { } if (pointer >= 0) { writer.tag(getVariableAbbrev()); - writer.writeInt(strings.stringRef("__class__")); - writer.ref(classClass.ptr, Blob::writeInt); + writer.writeInt(strings.stringRef("__classData__")); + writer.ref(classClass.getPointerPtr(), Blob::writeInt); var ops = new Blob(); - ops.writeByte(DW_OP_ADDR).writeInt(pointer).writeByte(DW_OP_STACK_VALUE); + ops.writeByte(DW_OP_ADDR).writeInt(pointer); writer.writeLEB(ops.size()); ops.newReader(writer::write).readRemaining(); } + if (isRoot) { + writeClassPointerField(); + } + writeFields(); writer.emptyTag(); } + + private void writeClassPointerField() { + writer.tag(getImmutableMemberAbbrev()); + writer.writeInt(strings.stringRef("__class__")); + writer.ref(classClass.ptr, Blob::writeInt); + var ops = new Blob(); + ops.writeByte(DW_OP_DEREF).writeByte(DW_OP_LIT3).writeByte(DW_OP_SHL); + writer.writeLEB(ops.size()); + ops.newReader(writer::write).readRemaining(); + writer.writeByte(DW_ACCESS_PUBLIC); + } + + private void writeFields() { + if (fields != null) { + for (var field : fields) { + field.write(); + } + } + } } public class Subprogram { @@ -395,4 +478,50 @@ public class DwarfClassGenerator { } } } + + abstract static class Field { + String name; + ValueType type; + int offset; + + Field(String name, ValueType type, int offset) { + this.name = name; + this.type = type; + this.offset = offset; + } + + abstract void write(); + } + + class InstanceField extends Field { + InstanceField(String name, ValueType type, int offset) { + super(name, type, offset); + } + + @Override + void write() { + writer.tag(getMemberAbbrev()); + writer.writeInt(strings.stringRef(name)); + writer.ref(getTypePtr(type), Blob::writeInt); + writer.writeShort(offset); + writer.writeByte(DW_ACCESS_PUBLIC); + } + } + + class StaticField extends Field { + StaticField(String name, ValueType type, int offset) { + super(name, type, offset); + } + + @Override + void write() { + writer.tag(getVariableAbbrev()); + writer.writeInt(strings.stringRef(name)); + writer.ref(getTypePtr(type), Blob::writeInt); + var ops = new Blob(); + ops.writeByte(DW_OP_ADDR).writeInt(offset); + writer.writeLEB(ops.size()); + ops.newReader(writer::write).readRemaining(); + } + } } 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 274dae66d..29c82f753 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 @@ -83,6 +83,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 78c37a94e..2c93fcec3 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 @@ -545,11 +545,20 @@ public class WasmClassGenerator { if (field.getInitialValue() != null) { setInitialValue(field.getType(), value, field.getInitialValue()); } - data.fieldLayout.put(field.getName(), binaryWriter.append(value)); + var address = binaryWriter.append(value); + data.fieldLayout.put(field.getName(), address); + if (dwarfClass != null) { + dwarfClass.registerStaticField(field.getName(), field.getType(), address); + dwarfClassGenerator.getTypePtr(field.getType()); + } } else { int offset = align(data.size, desiredAlignment); data.fieldLayout.put(field.getName(), offset); data.size = offset + desiredAlignment; + if (dwarfClass != null) { + dwarfClass.registerField(field.getName(), field.getType(), offset); + dwarfClassGenerator.getTypePtr(field.getType()); + } } if (data.alignment == 0) { data.alignment = desiredAlignment; @@ -720,7 +729,6 @@ public class WasmClassGenerator { } else if (data.type instanceof ValueType.Object) { var className = ((ValueType.Object) data.type).getClassName(); if (className.equals("java.lang.Class")) { - int headerSize = 8; debug.startClass(className, indexes.get(ValueType.object("java.lang.Object")), data.start, 60); debug.instanceField("size", 8, FieldType.INT); debug.instanceField("flags", 12, FieldType.INT);