Wasm: split declarations and specifications of methods in DWARF

This commit is contained in:
Alexey Andreev 2022-11-21 16:00:27 +01:00
parent 8fac3237ba
commit 13cc56feb5
4 changed files with 81 additions and 28 deletions

View File

@ -547,8 +547,11 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
} }
var writer = new WasmBinaryWriter(); var writer = new WasmBinaryWriter();
if (dwarfClassGen != null) {
dwarfClassGen.write(dwarfGenerator.getInfoWriter(), dwarfGenerator.strings);
}
var renderer = new WasmBinaryRenderer(writer, version, obfuscated, dwarfGenerator, dwarfClassGen); 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)) { try (OutputStream output = buildTarget.createResource(outputName)) {
output.write(writer.getData()); output.write(writer.getData());
@ -567,13 +570,11 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
} }
} }
private Supplier<Collection<? extends WasmCustomSection>> buildDwarf(DwarfGenerator generator, private Supplier<Collection<? extends WasmCustomSection>> buildDwarf(DwarfGenerator generator) {
DwarfClassGenerator classGen) {
if (generator == null) { if (generator == null) {
return null; return null;
} }
return () -> { return () -> {
classGen.write(generator.getInfoWriter(), generator.strings);
generator.end(); generator.end();
return generator.createSections(); return generator.createSections();
}; };

View File

@ -31,6 +31,9 @@ public final class DwarfConstants {
public static final int DW_AT_HIGH_PC = 0x12; public static final int DW_AT_HIGH_PC = 0x12;
public static final int DW_AT_LANGUAGE = 0x13; public static final int DW_AT_LANGUAGE = 0x13;
public static final int DW_AT_PRODUCER = 0x25; 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; 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_ADDR = 0x01;
public static final int DW_FORM_DATA2 = 0x05; public static final int DW_FORM_DATA2 = 0x05;
public static final int DW_FORM_DATA4 = 0x06; 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_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_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_FORM_LINE_STRP = 0x1F;
public static final int DW_LNS_COPY = 0x01; public static final int DW_LNS_COPY = 0x01;

View File

@ -15,10 +15,9 @@
*/ */
package org.teavm.backend.wasm.generate; 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_DECLARATION;
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_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_FORM_STRP;
import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_CLASS_TYPE; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_CLASS_TYPE;
import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_NAMESPACE; import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_NAMESPACE;
@ -30,6 +29,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.teavm.backend.wasm.dwarf.DwarfAbbreviation; import org.teavm.backend.wasm.dwarf.DwarfAbbreviation;
import org.teavm.backend.wasm.dwarf.DwarfInfoWriter; import org.teavm.backend.wasm.dwarf.DwarfInfoWriter;
import org.teavm.backend.wasm.dwarf.DwarfPlaceholder;
import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodDescriptor;
public class DwarfClassGenerator { public class DwarfClassGenerator {
@ -64,13 +64,6 @@ public class DwarfClassGenerator {
return subprogramsByFunctionName.get(functionName); 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) { public void write(DwarfInfoWriter infoWriter, DwarfStrings strings) {
this.infoWriter = infoWriter; this.infoWriter = infoWriter;
this.strings = strings; this.strings = strings;
@ -87,8 +80,7 @@ public class DwarfClassGenerator {
if (methodAbbrev == null) { if (methodAbbrev == null) {
methodAbbrev = infoWriter.abbreviation(DW_TAG_SUBPROGRAM, true, data -> { methodAbbrev = infoWriter.abbreviation(DW_TAG_SUBPROGRAM, true, data -> {
data.writeLEB(DW_AT_NAME).writeLEB(DW_FORM_STRP); data.writeLEB(DW_AT_NAME).writeLEB(DW_FORM_STRP);
data.writeLEB(DW_AT_LOW_PC).writeLEB(DW_FORM_ADDR); data.writeLEB(DW_AT_DECLARATION).writeLEB(DW_FORM_FLAG_PRESENT);
data.writeLEB(DW_AT_HIGH_PC).writeLEB(DW_FORM_ADDR);
}); });
} }
return methodAbbrev; return methodAbbrev;
@ -170,18 +162,16 @@ public class DwarfClassGenerator {
public class Subprogram { public class Subprogram {
public final String name; public final String name;
public int startAddress; public DwarfPlaceholder ref;
public int endAddress;
private Subprogram(String name) { private Subprogram(String name) {
this.name = name; this.name = name;
} }
private void write() { private void write() {
infoWriter.tag(getMethodAbbrev()); ref = infoWriter.placeholder(4);
infoWriter.mark(ref).tag(getMethodAbbrev());
infoWriter.writeInt(strings.stringRef(name)); infoWriter.writeInt(strings.stringRef(name));
infoWriter.writeInt(startAddress);
infoWriter.writeInt(endAddress);
infoWriter.emptyTag(); infoWriter.emptyTag();
} }
} }

View File

@ -15,6 +15,14 @@
*/ */
package org.teavm.backend.wasm.render; 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.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -23,6 +31,9 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; 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.DwarfClassGenerator;
import org.teavm.backend.wasm.generate.DwarfGenerator; import org.teavm.backend.wasm.generate.DwarfGenerator;
import org.teavm.backend.wasm.model.WasmCustomSection; import org.teavm.backend.wasm.model.WasmCustomSection;
@ -57,6 +68,8 @@ public class WasmBinaryRenderer {
private boolean obfuscated; private boolean obfuscated;
private DwarfGenerator dwarfGenerator; private DwarfGenerator dwarfGenerator;
private DwarfClassGenerator dwarfClassGen; private DwarfClassGenerator dwarfClassGen;
private DwarfAbbreviation methodAbbrev;
private DwarfAbbreviation functionAbbrev;
public WasmBinaryRenderer(WasmBinaryWriter output, WasmBinaryVersion version, boolean obfuscated, public WasmBinaryRenderer(WasmBinaryWriter output, WasmBinaryVersion version, boolean obfuscated,
DwarfGenerator dwarfGenerator, DwarfClassGenerator dwarfClassGen) { DwarfGenerator dwarfGenerator, DwarfClassGenerator dwarfClassGen) {
@ -286,6 +299,25 @@ public class WasmBinaryRenderer {
private byte[] renderFunction(WasmFunction function, int offset) { private byte[] renderFunction(WasmFunction function, int offset) {
var code = new WasmBinaryWriter(); 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<WasmLocal> localVariables = function.getLocalVariables(); List<WasmLocal> localVariables = function.getLocalVariables();
int parameterCount = Math.min(function.getParameters().size(), localVariables.size()); int parameterCount = Math.min(function.getParameters().size(), localVariables.size());
localVariables = localVariables.subList(parameterCount, localVariables.size()); localVariables = localVariables.subList(parameterCount, localVariables.size());
@ -324,13 +356,14 @@ public class WasmBinaryRenderer {
} }
code.writeByte(0x0B); code.writeByte(0x0B);
if (dwarfClassGen != null && function.getName() != null) {
var dwarfSubprogram = dwarfClassGen.getSubprogram(function.getName()); if (endProgramMarker != null) {
if (dwarfSubprogram == null) { var dwarfWriter = dwarfGenerator.getInfoWriter();
dwarfSubprogram = dwarfClassGen.createSubprogram(function.getName()); var backup = dwarfWriter.marker();
} endProgramMarker.rewind();
dwarfSubprogram.startAddress = offset; dwarfWriter.writeInt(offset + code.getPosition());
dwarfSubprogram.endAddress = offset + code.getPosition(); backup.rewind();
dwarfWriter.emptyTag();
} }
return code.getData(); return code.getData();
@ -432,4 +465,27 @@ public class WasmBinaryRenderer {
output.writeBytes(data); 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;
}
} }