wasm: generate field description in DWARF

This commit is contained in:
Alexey Andreev 2023-08-26 20:48:29 +02:00
parent fed6a2d0ef
commit cacf09dca8
4 changed files with 161 additions and 8 deletions

View File

@ -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() {
}
}

View File

@ -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<MethodDescriptor, Subprogram> subprograms = new LinkedHashMap<>();
List<Field> 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();
}
}
}

View File

@ -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();
}

View File

@ -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);