From 13cc56feb53fe175efed79d293bafb15878d43e8 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Mon, 21 Nov 2022 16:00:27 +0100 Subject: [PATCH] Wasm: split declarations and specifications of methods in DWARF --- .../org/teavm/backend/wasm/WasmTarget.java | 9 +-- .../backend/wasm/dwarf/DwarfConstants.java | 6 ++ .../wasm/generate/DwarfClassGenerator.java | 24 ++----- .../wasm/render/WasmBinaryRenderer.java | 70 +++++++++++++++++-- 4 files changed, 81 insertions(+), 28 deletions(-) diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java index 85496b476..c7cd5cc31 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java @@ -547,8 +547,11 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost { } var writer = new WasmBinaryWriter(); + if (dwarfClassGen != null) { + dwarfClassGen.write(dwarfGenerator.getInfoWriter(), dwarfGenerator.strings); + } var renderer = new WasmBinaryRenderer(writer, version, obfuscated, dwarfGenerator, dwarfClassGen); - renderer.render(module, buildDwarf(dwarfGenerator, dwarfClassGen)); + renderer.render(module, buildDwarf(dwarfGenerator)); try (OutputStream output = buildTarget.createResource(outputName)) { output.write(writer.getData()); @@ -567,13 +570,11 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost { } } - private Supplier> buildDwarf(DwarfGenerator generator, - DwarfClassGenerator classGen) { + private Supplier> buildDwarf(DwarfGenerator generator) { if (generator == null) { return null; } return () -> { - classGen.write(generator.getInfoWriter(), generator.strings); generator.end(); return generator.createSections(); }; 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 48f64499f..5de555cda 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 @@ -31,6 +31,9 @@ public final class DwarfConstants { public static final int DW_AT_HIGH_PC = 0x12; public static final int DW_AT_LANGUAGE = 0x13; public static final int DW_AT_PRODUCER = 0x25; + public static final int DW_AT_DECLARATION = 0x3c; + public static final int DW_AT_SPECIFICATION = 0x47; + public static final int DW_AT_LINKAGE_NAME = 0x6E; public static final int DW_LANG_JAVA = 0x0b; @@ -43,8 +46,11 @@ public final class DwarfConstants { public static final int DW_FORM_ADDR = 0x01; public static final int DW_FORM_DATA2 = 0x05; public static final int DW_FORM_DATA4 = 0x06; + public static final int DW_FORM_FLAG = 0x0C; public static final int DW_FORM_STRP = 0x0E; + public static final int DW_FORM_REF4 = 0x13; public static final int DW_FORM_SEC_OFFSET = 0x17; + public static final int DW_FORM_FLAG_PRESENT = 0x19; public static final int DW_FORM_LINE_STRP = 0x1F; public static final int DW_LNS_COPY = 0x01; 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 f788713a7..643d0971a 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,10 +15,9 @@ */ package org.teavm.backend.wasm.generate; -import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_HIGH_PC; -import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_LOW_PC; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_DECLARATION; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_NAME; -import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_FORM_ADDR; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_FORM_FLAG_PRESENT; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_FORM_STRP; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_CLASS_TYPE; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_NAMESPACE; @@ -30,6 +29,7 @@ import java.util.List; import java.util.Map; import org.teavm.backend.wasm.dwarf.DwarfAbbreviation; import org.teavm.backend.wasm.dwarf.DwarfInfoWriter; +import org.teavm.backend.wasm.dwarf.DwarfPlaceholder; import org.teavm.model.MethodDescriptor; public class DwarfClassGenerator { @@ -64,13 +64,6 @@ public class DwarfClassGenerator { return subprogramsByFunctionName.get(functionName); } - public Subprogram createSubprogram(String functionName) { - var subprogram = new Subprogram(functionName); - subprogramsByFunctionName.put(functionName, subprogram); - rootSubprograms.add(subprogram); - return subprogram; - } - public void write(DwarfInfoWriter infoWriter, DwarfStrings strings) { this.infoWriter = infoWriter; this.strings = strings; @@ -87,8 +80,7 @@ public class DwarfClassGenerator { if (methodAbbrev == null) { methodAbbrev = infoWriter.abbreviation(DW_TAG_SUBPROGRAM, true, data -> { data.writeLEB(DW_AT_NAME).writeLEB(DW_FORM_STRP); - data.writeLEB(DW_AT_LOW_PC).writeLEB(DW_FORM_ADDR); - data.writeLEB(DW_AT_HIGH_PC).writeLEB(DW_FORM_ADDR); + data.writeLEB(DW_AT_DECLARATION).writeLEB(DW_FORM_FLAG_PRESENT); }); } return methodAbbrev; @@ -170,18 +162,16 @@ public class DwarfClassGenerator { public class Subprogram { public final String name; - public int startAddress; - public int endAddress; + public DwarfPlaceholder ref; private Subprogram(String name) { this.name = name; } private void write() { - infoWriter.tag(getMethodAbbrev()); + ref = infoWriter.placeholder(4); + infoWriter.mark(ref).tag(getMethodAbbrev()); infoWriter.writeInt(strings.stringRef(name)); - infoWriter.writeInt(startAddress); - infoWriter.writeInt(endAddress); infoWriter.emptyTag(); } } diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java index 9ebf5e2ad..4b1a1d0fe 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java @@ -15,6 +15,14 @@ */ package org.teavm.backend.wasm.render; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_HIGH_PC; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_LOW_PC; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_NAME; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_AT_SPECIFICATION; +import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_FORM_ADDR; +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_TAG_SUBPROGRAM; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -23,6 +31,9 @@ import java.util.List; import java.util.Map; import java.util.function.Supplier; import java.util.stream.Collectors; +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.generate.DwarfClassGenerator; import org.teavm.backend.wasm.generate.DwarfGenerator; import org.teavm.backend.wasm.model.WasmCustomSection; @@ -57,6 +68,8 @@ public class WasmBinaryRenderer { private boolean obfuscated; private DwarfGenerator dwarfGenerator; private DwarfClassGenerator dwarfClassGen; + private DwarfAbbreviation methodAbbrev; + private DwarfAbbreviation functionAbbrev; public WasmBinaryRenderer(WasmBinaryWriter output, WasmBinaryVersion version, boolean obfuscated, DwarfGenerator dwarfGenerator, DwarfClassGenerator dwarfClassGen) { @@ -286,6 +299,25 @@ public class WasmBinaryRenderer { private byte[] renderFunction(WasmFunction function, int offset) { var code = new WasmBinaryWriter(); + Marker endProgramMarker; + if (dwarfClassGen != null && function.getName() != null) { + var dwarfSubprogram = dwarfClassGen.getSubprogram(function.getName()); + var writer = dwarfGenerator.getInfoWriter(); + var strings = dwarfGenerator.strings; + writer.tag(dwarfSubprogram != null ? getMethodAbbrev() : getFunctionAbbrev()); + if (dwarfSubprogram != null) { + writer.ref(dwarfSubprogram.ref, Blob::writeInt); + } else { + writer.writeInt(strings.stringRef( + dwarfSubprogram != null ? dwarfSubprogram.name : function.getName())); + } + writer.writeInt(offset); + endProgramMarker = writer.marker(); + writer.skip(4); + } else { + endProgramMarker = null; + } + List localVariables = function.getLocalVariables(); int parameterCount = Math.min(function.getParameters().size(), localVariables.size()); localVariables = localVariables.subList(parameterCount, localVariables.size()); @@ -324,13 +356,14 @@ public class WasmBinaryRenderer { } code.writeByte(0x0B); - if (dwarfClassGen != null && function.getName() != null) { - var dwarfSubprogram = dwarfClassGen.getSubprogram(function.getName()); - if (dwarfSubprogram == null) { - dwarfSubprogram = dwarfClassGen.createSubprogram(function.getName()); - } - dwarfSubprogram.startAddress = offset; - dwarfSubprogram.endAddress = offset + code.getPosition(); + + if (endProgramMarker != null) { + var dwarfWriter = dwarfGenerator.getInfoWriter(); + var backup = dwarfWriter.marker(); + endProgramMarker.rewind(); + dwarfWriter.writeInt(offset + code.getPosition()); + backup.rewind(); + dwarfWriter.emptyTag(); } return code.getData(); @@ -432,4 +465,27 @@ public class WasmBinaryRenderer { output.writeBytes(data); } + + + private DwarfAbbreviation getMethodAbbrev() { + if (methodAbbrev == null) { + methodAbbrev = dwarfGenerator.getInfoWriter().abbreviation(DW_TAG_SUBPROGRAM, true, data -> { + data.writeLEB(DW_AT_SPECIFICATION).writeLEB(DW_FORM_REF4); + data.writeLEB(DW_AT_LOW_PC).writeLEB(DW_FORM_ADDR); + data.writeLEB(DW_AT_HIGH_PC).writeLEB(DW_FORM_ADDR); + }); + } + return methodAbbrev; + } + + private DwarfAbbreviation getFunctionAbbrev() { + if (functionAbbrev == null) { + functionAbbrev = dwarfGenerator.getInfoWriter().abbreviation(DW_TAG_SUBPROGRAM, true, data -> { + data.writeLEB(DW_AT_NAME).writeLEB(DW_FORM_STRP); + data.writeLEB(DW_AT_LOW_PC).writeLEB(DW_FORM_ADDR); + data.writeLEB(DW_AT_HIGH_PC).writeLEB(DW_FORM_ADDR); + }); + } + return functionAbbrev; + } }