mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Wasm: add information about parameters and local variables to DWARF
This commit is contained in:
parent
13cc56feb5
commit
f938db798b
|
@ -446,7 +446,14 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
BinaryWriter binaryWriter = new BinaryWriter(256);
|
||||
var names = new NameProviderWithSpecialNames(new WasmNameProvider(), controller.getUnprocessedClassSource());
|
||||
var metadataRequirements = new ClassMetadataRequirements(controller.getDependencyInfo());
|
||||
var dwarfClassGen = debugging ? new DwarfClassGenerator() : null;
|
||||
|
||||
var dwarfGenerator = debugging ? new DwarfGenerator() : null;
|
||||
if (dwarfGenerator != null) {
|
||||
dwarfGenerator.begin();
|
||||
}
|
||||
var dwarfClassGen = debugging
|
||||
? new DwarfClassGenerator(dwarfGenerator.getInfoWriter(), dwarfGenerator.strings)
|
||||
: null;
|
||||
var classGenerator = new WasmClassGenerator(classes, controller.getUnprocessedClassSource(),
|
||||
vtableProvider, tagRegistry, binaryWriter, names, metadataRequirements,
|
||||
controller.getClassInitializerInfo(), characteristics, dwarfClassGen);
|
||||
|
@ -496,10 +503,6 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
classGenerator, stringPool, obfuscated);
|
||||
context.addIntrinsic(exceptionHandlingIntrinsic);
|
||||
|
||||
var dwarfGenerator = debugging ? new DwarfGenerator() : null;
|
||||
if (dwarfGenerator != null) {
|
||||
dwarfGenerator.begin();
|
||||
}
|
||||
var generator = new WasmGenerator(decompiler, classes, context, classGenerator, binaryWriter,
|
||||
asyncMethods::contains);
|
||||
|
||||
|
@ -547,11 +550,8 @@ 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));
|
||||
renderer.render(module, buildDwarf(dwarfGenerator, dwarfClassGen));
|
||||
|
||||
try (OutputStream output = buildTarget.createResource(outputName)) {
|
||||
output.write(writer.getData());
|
||||
|
@ -570,11 +570,13 @@ 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) {
|
||||
return null;
|
||||
}
|
||||
return () -> {
|
||||
classGen.write();
|
||||
generator.end();
|
||||
return generator.createSections();
|
||||
};
|
||||
|
@ -781,6 +783,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
if (dwarfClassGen != null) {
|
||||
var dwarfClass = dwarfClassGen.getClass(method.getOwnerName());
|
||||
var dwarfSubprogram = dwarfClass.getSubprogram(method.getDescriptor());
|
||||
dwarfSubprogram.isStatic = method.hasModifier(ElementModifier.STATIC);
|
||||
dwarfClassGen.registerSubprogram(context.names.forMethod(method.getReference()), dwarfSubprogram);
|
||||
}
|
||||
if (controller.wasCancelled()) {
|
||||
|
|
|
@ -21,20 +21,36 @@ public final class DwarfConstants {
|
|||
public static final int DW_UT_COMPILE = 0x01;
|
||||
|
||||
public static final int DW_TAG_CLASS_TYPE = 0x02;
|
||||
public static final int DW_TAG_FORMAL_PARAMETER = 0x05;
|
||||
public static final int DW_TAG_COMPILE_UNIT = 0x11;
|
||||
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;
|
||||
public static final int DW_TAG_NAMESPACE = 0x39;
|
||||
public static final int DW_TAG_UNSPECIFIED_TYPE = 0x3B;
|
||||
|
||||
public static final int DW_AT_LOCATION = 0x02;
|
||||
public static final int DW_AT_NAME = 0x03;
|
||||
public static final int DW_AT_BYTE_SIZE = 0x0B;
|
||||
public static final int DW_AT_STMT_LIST = 0x10;
|
||||
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_PRODUCER = 0x25;
|
||||
public static final int DW_AT_DECLARATION = 0x3c;
|
||||
public static final int DW_AT_DECLARATION = 0x3C;
|
||||
public static final int DW_AT_ENCODING = 0x3E;
|
||||
public static final int DW_AT_SPECIFICATION = 0x47;
|
||||
public static final int DW_AT_TYPE = 0x49;
|
||||
public static final int DW_AT_LINKAGE_NAME = 0x6E;
|
||||
|
||||
public static final int DW_ATE_ADDRESS = 0x01;
|
||||
public static final int DW_ATE_BOOLEAN = 0x02;
|
||||
public static final int DW_ATE_FLOAT = 0x04;
|
||||
public static final int DW_ATE_SIGNED = 0x05;
|
||||
public static final int DW_ATE_UNSIGNED = 0x07;
|
||||
public static final int DW_ATE_UNSIGNED_CHAR = 0x08;
|
||||
public static final int DW_ATE_UTF = 0x10;
|
||||
|
||||
public static final int DW_LANG_JAVA = 0x0b;
|
||||
|
||||
public static final int DW_CHILDREN_YES = 1;
|
||||
|
@ -46,13 +62,17 @@ 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_DATA1 = 0x0B;
|
||||
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_EXPRLOC = 0x18;
|
||||
public static final int DW_FORM_FLAG_PRESENT = 0x19;
|
||||
public static final int DW_FORM_LINE_STRP = 0x1F;
|
||||
|
||||
public static final int DW_OP_WASM_LOCATION = 0xED;
|
||||
|
||||
public static final int DW_LNS_COPY = 0x01;
|
||||
public static final int DW_LNS_ADVANCE_PC = 0x02;
|
||||
public static final int DW_LNS_ADVANCE_LINE = 0x03;
|
||||
|
|
|
@ -15,13 +15,22 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.generate;
|
||||
|
||||
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_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_NAME;
|
||||
import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_FORM_DATA1;
|
||||
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_BASE_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_SUBPROGRAM;
|
||||
import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_UNSPECIFIED_TYPE;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
|
@ -31,16 +40,36 @@ 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;
|
||||
import org.teavm.model.PrimitiveType;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.util.VariableType;
|
||||
|
||||
public class DwarfClassGenerator {
|
||||
private static final ValueType objectType = ValueType.object("java.lang.Object");
|
||||
final Namespace root = new Namespace(null);
|
||||
final Map<String, Subprogram> subprogramsByFunctionName = new HashMap<>();
|
||||
final List<Subprogram> rootSubprograms = new ArrayList<>();
|
||||
private DwarfInfoWriter infoWriter;
|
||||
private DwarfStrings strings;
|
||||
private final DwarfInfoWriter writer;
|
||||
private final DwarfStrings strings;
|
||||
private DwarfAbbreviation nsAbbrev;
|
||||
private DwarfAbbreviation classTypeAbbrev;
|
||||
private DwarfAbbreviation methodAbbrev;
|
||||
private DwarfPlaceholder[] primitiveTypes = new DwarfPlaceholder[PrimitiveType.values().length];
|
||||
private DwarfPlaceholder unspecifiedType;
|
||||
private DwarfAbbreviation baseTypeAbbrev;
|
||||
private List<Runnable> postponedWrites = new ArrayList<>();
|
||||
|
||||
public DwarfClassGenerator(DwarfInfoWriter writer, DwarfStrings strings) {
|
||||
this.writer = writer;
|
||||
this.strings = strings;
|
||||
}
|
||||
|
||||
public void flushTypes() {
|
||||
for (var postponedWrite : postponedWrites) {
|
||||
postponedWrite.run();
|
||||
}
|
||||
postponedWrites.clear();
|
||||
}
|
||||
|
||||
public ClassType getClass(String fullName) {
|
||||
var index = 0;
|
||||
|
@ -64,21 +93,16 @@ public class DwarfClassGenerator {
|
|||
return subprogramsByFunctionName.get(functionName);
|
||||
}
|
||||
|
||||
public void write(DwarfInfoWriter infoWriter, DwarfStrings strings) {
|
||||
this.infoWriter = infoWriter;
|
||||
this.strings = strings;
|
||||
public void write() {
|
||||
root.writeChildren();
|
||||
for (var subprogram : rootSubprograms) {
|
||||
subprogram.write();
|
||||
}
|
||||
this.infoWriter = null;
|
||||
this.strings = null;
|
||||
methodAbbrev = null;
|
||||
}
|
||||
|
||||
private DwarfAbbreviation getMethodAbbrev() {
|
||||
if (methodAbbrev == null) {
|
||||
methodAbbrev = infoWriter.abbreviation(DW_TAG_SUBPROGRAM, true, data -> {
|
||||
methodAbbrev = writer.abbreviation(DW_TAG_SUBPROGRAM, true, data -> {
|
||||
data.writeLEB(DW_AT_NAME).writeLEB(DW_FORM_STRP);
|
||||
data.writeLEB(DW_AT_DECLARATION).writeLEB(DW_FORM_FLAG_PRESENT);
|
||||
});
|
||||
|
@ -88,7 +112,7 @@ public class DwarfClassGenerator {
|
|||
|
||||
private DwarfAbbreviation getNsAbbrev() {
|
||||
if (nsAbbrev == null) {
|
||||
nsAbbrev = infoWriter.abbreviation(DW_TAG_NAMESPACE, true, data -> {
|
||||
nsAbbrev = writer.abbreviation(DW_TAG_NAMESPACE, true, data -> {
|
||||
data.writeLEB(DW_AT_NAME).writeLEB(DW_FORM_STRP);
|
||||
});
|
||||
}
|
||||
|
@ -97,13 +121,127 @@ public class DwarfClassGenerator {
|
|||
|
||||
private DwarfAbbreviation getClassTypeAbbrev() {
|
||||
if (classTypeAbbrev == null) {
|
||||
classTypeAbbrev = infoWriter.abbreviation(DW_TAG_CLASS_TYPE, true, data -> {
|
||||
classTypeAbbrev = writer.abbreviation(DW_TAG_CLASS_TYPE, true, data -> {
|
||||
data.writeLEB(DW_AT_NAME).writeLEB(DW_FORM_STRP);
|
||||
});
|
||||
}
|
||||
return classTypeAbbrev;
|
||||
}
|
||||
|
||||
public DwarfPlaceholder getTypePtr(VariableType type) {
|
||||
switch (type) {
|
||||
case INT:
|
||||
return getPrimitivePtr(ValueType.Primitive.INTEGER);
|
||||
case LONG:
|
||||
return getPrimitivePtr(ValueType.Primitive.LONG);
|
||||
case FLOAT:
|
||||
return getPrimitivePtr(ValueType.Primitive.FLOAT);
|
||||
case DOUBLE:
|
||||
return getPrimitivePtr(ValueType.Primitive.DOUBLE);
|
||||
default:
|
||||
return getTypePtr(objectType);
|
||||
}
|
||||
}
|
||||
|
||||
public DwarfPlaceholder getTypePtr(ValueType type) {
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
return getPrimitivePtr((ValueType.Primitive) type);
|
||||
} else if (type instanceof ValueType.Object) {
|
||||
return getClassType(((ValueType.Object) type).getClassName());
|
||||
}
|
||||
return getClassType("java.lang.Object");
|
||||
}
|
||||
|
||||
private DwarfPlaceholder getUnspecifiedType() {
|
||||
if (unspecifiedType == null) {
|
||||
unspecifiedType = writer.placeholder(4);
|
||||
var abbrev = writer.abbreviation(DW_TAG_UNSPECIFIED_TYPE, false, blob -> {
|
||||
blob.writeInt(DW_AT_NAME).writeInt(DW_FORM_STRP);
|
||||
});
|
||||
writer.mark(unspecifiedType).tag(abbrev).writeInt(strings.stringRef("<unspecified>"));
|
||||
}
|
||||
return unspecifiedType;
|
||||
}
|
||||
|
||||
private DwarfPlaceholder getClassType(String name) {
|
||||
return getClass(name).ptr;
|
||||
}
|
||||
|
||||
private DwarfPlaceholder getPrimitivePtr(ValueType.Primitive type) {
|
||||
var result = primitiveTypes[type.getKind().ordinal()];
|
||||
if (result == null) {
|
||||
String name;
|
||||
int byteSize;
|
||||
int encoding;
|
||||
switch (type.getKind()) {
|
||||
case BOOLEAN:
|
||||
name = "boolean";
|
||||
byteSize = 1;
|
||||
encoding = DW_ATE_BOOLEAN;
|
||||
break;
|
||||
case BYTE:
|
||||
name = "byte";
|
||||
byteSize = 1;
|
||||
encoding = DW_ATE_SIGNED;
|
||||
break;
|
||||
case SHORT:
|
||||
name = "short";
|
||||
byteSize = 2;
|
||||
encoding = DW_ATE_SIGNED;
|
||||
break;
|
||||
case CHARACTER:
|
||||
name = "char";
|
||||
byteSize = 2;
|
||||
encoding = DW_ATE_UTF;
|
||||
break;
|
||||
case INTEGER:
|
||||
name = "int";
|
||||
byteSize = 4;
|
||||
encoding = DW_ATE_SIGNED;
|
||||
break;
|
||||
case LONG:
|
||||
name = "long";
|
||||
byteSize = 8;
|
||||
encoding = DW_ATE_SIGNED;
|
||||
break;
|
||||
case FLOAT:
|
||||
name = "float";
|
||||
encoding = DW_ATE_FLOAT;
|
||||
byteSize = 4;
|
||||
break;
|
||||
case DOUBLE:
|
||||
name = "double";
|
||||
encoding = DW_ATE_FLOAT;
|
||||
byteSize = 8;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
var ptr = writer.placeholder(4);
|
||||
postponedWrites.add(() -> {
|
||||
writer.mark(ptr).tag(getBaseTypeAbbrev());
|
||||
writer.writeInt(strings.stringRef(name));
|
||||
writer.writeByte(byteSize);
|
||||
writer.writeByte(encoding);
|
||||
});
|
||||
result = ptr;
|
||||
primitiveTypes[type.getKind().ordinal()] = ptr;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private DwarfAbbreviation getBaseTypeAbbrev() {
|
||||
if (baseTypeAbbrev == null) {
|
||||
baseTypeAbbrev = writer.abbreviation(DW_TAG_BASE_TYPE, false, blob -> {
|
||||
blob.writeLEB(DW_AT_NAME).writeLEB(DW_FORM_STRP);
|
||||
blob.writeLEB(DW_AT_BYTE_SIZE).writeLEB(DW_FORM_DATA1);
|
||||
blob.writeLEB(DW_AT_ENCODING).writeLEB(DW_FORM_DATA1);
|
||||
});
|
||||
}
|
||||
return baseTypeAbbrev;
|
||||
}
|
||||
|
||||
public class Namespace {
|
||||
public final String name;
|
||||
final Map<String, Namespace> namespaces = new LinkedHashMap<>();
|
||||
|
@ -118,10 +256,10 @@ public class DwarfClassGenerator {
|
|||
}
|
||||
|
||||
private void write() {
|
||||
infoWriter.tag(getNsAbbrev());
|
||||
infoWriter.writeInt(strings.stringRef(name));
|
||||
writer.tag(getNsAbbrev());
|
||||
writer.writeInt(strings.stringRef(name));
|
||||
writeChildren();
|
||||
infoWriter.emptyTag();
|
||||
writer.emptyTag();
|
||||
}
|
||||
|
||||
private void writeChildren() {
|
||||
|
@ -140,39 +278,44 @@ public class DwarfClassGenerator {
|
|||
|
||||
public class ClassType {
|
||||
public final String name;
|
||||
final DwarfPlaceholder ptr;
|
||||
final Map<MethodDescriptor, Subprogram> subprograms = new LinkedHashMap<>();
|
||||
|
||||
private ClassType(String name) {
|
||||
ptr = writer.placeholder(4);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Subprogram getSubprogram(MethodDescriptor desc) {
|
||||
return subprograms.computeIfAbsent(desc, d -> new Subprogram(d.getName()));
|
||||
return subprograms.computeIfAbsent(desc, d -> new Subprogram(d.getName(), desc));
|
||||
}
|
||||
|
||||
private void write() {
|
||||
infoWriter.tag(getClassTypeAbbrev());
|
||||
infoWriter.writeInt(strings.stringRef(name));
|
||||
writer.mark(ptr).tag(getClassTypeAbbrev());
|
||||
writer.writeInt(strings.stringRef(name));
|
||||
for (var child : subprograms.values()) {
|
||||
child.write();
|
||||
}
|
||||
infoWriter.emptyTag();
|
||||
writer.emptyTag();
|
||||
}
|
||||
}
|
||||
|
||||
public class Subprogram {
|
||||
public final String name;
|
||||
public DwarfPlaceholder ref;
|
||||
public boolean isStatic;
|
||||
public final MethodDescriptor descriptor;
|
||||
public final DwarfPlaceholder ref;
|
||||
|
||||
private Subprogram(String name) {
|
||||
private Subprogram(String name, MethodDescriptor descriptor) {
|
||||
this.name = name;
|
||||
this.descriptor = descriptor;
|
||||
ref = writer.placeholder(4);
|
||||
}
|
||||
|
||||
private void write() {
|
||||
ref = infoWriter.placeholder(4);
|
||||
infoWriter.mark(ref).tag(getMethodAbbrev());
|
||||
infoWriter.writeInt(strings.stringRef(name));
|
||||
infoWriter.emptyTag();
|
||||
writer.mark(ref).tag(getMethodAbbrev());
|
||||
writer.writeInt(strings.stringRef(name));
|
||||
writer.emptyTag();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright 2022 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
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_LOCATION;
|
||||
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_AT_TYPE;
|
||||
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_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;
|
||||
import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_VARIABLE;
|
||||
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;
|
||||
|
||||
public class DwarfFunctionGenerator {
|
||||
private DwarfClassGenerator classGen;
|
||||
private DwarfGenerator generator;
|
||||
private WasmFunction function;
|
||||
private int offset;
|
||||
private Marker endProgramMarker;
|
||||
private DwarfAbbreviation methodAbbrev;
|
||||
private DwarfAbbreviation functionAbbrev;
|
||||
private DwarfAbbreviation parameterAbbrev;
|
||||
private DwarfAbbreviation variableAbbrev;
|
||||
private DwarfClassGenerator.Subprogram subprogram;
|
||||
|
||||
public DwarfFunctionGenerator(DwarfClassGenerator classGen, DwarfGenerator generator) {
|
||||
this.classGen = classGen;
|
||||
this.generator = generator;
|
||||
}
|
||||
|
||||
public void begin(WasmFunction function, int offset) {
|
||||
if (function.getName() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
subprogram = classGen.getSubprogram(function.getName());
|
||||
var writer = generator.getInfoWriter();
|
||||
var strings = generator.strings;
|
||||
writer.tag(subprogram != null ? getMethodAbbrev() : getFunctionAbbrev());
|
||||
if (subprogram != null) {
|
||||
writer.ref(subprogram.ref, Blob::writeInt);
|
||||
} else {
|
||||
writer.writeInt(strings.stringRef(subprogram != null ? subprogram.name : function.getName()));
|
||||
}
|
||||
writer.writeInt(offset);
|
||||
endProgramMarker = writer.marker();
|
||||
writer.skip(4);
|
||||
|
||||
this.function = function;
|
||||
this.offset = offset;
|
||||
|
||||
writeLocals();
|
||||
}
|
||||
|
||||
private void writeLocals() {
|
||||
if (subprogram == null) {
|
||||
return;
|
||||
}
|
||||
var descriptor = subprogram.descriptor;
|
||||
if (descriptor == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var writer = generator.getInfoWriter();
|
||||
var strings = generator.strings;
|
||||
var offset = subprogram.isStatic ? 0 : 1;
|
||||
int count = Math.min(function.getLocalVariables().size() - offset, descriptor.parameterCount());
|
||||
for (var i = 0; i < count; ++i) {
|
||||
var local = function.getLocalVariables().get(i + offset);
|
||||
if (local.getName() == null) {
|
||||
continue;
|
||||
}
|
||||
writer.tag(getParameterAbbrev());
|
||||
writer.writeInt(strings.stringRef(local.getName()));
|
||||
writer.ref(classGen.getTypePtr(descriptor.parameterType(i)), Blob::writeInt);
|
||||
|
||||
var operations = new Blob();
|
||||
operations.writeByte(DW_OP_WASM_LOCATION).writeByte(0).writeLEB(i + 1);
|
||||
writer.writeLEB(operations.size());
|
||||
operations.newReader(writer::write).readRemaining();
|
||||
}
|
||||
|
||||
for (var i = count + offset; i < function.getLocalVariables().size(); ++i) {
|
||||
var local = function.getLocalVariables().get(i);
|
||||
if (local.getName() == null || local.getJavaType() == null) {
|
||||
continue;
|
||||
}
|
||||
writer.tag(getVariableAbbrev());
|
||||
writer.writeInt(strings.stringRef(local.getName()));
|
||||
writer.ref(classGen.getTypePtr(local.getJavaType()), Blob::writeInt);
|
||||
|
||||
var operations = new Blob();
|
||||
operations.writeByte(DW_OP_WASM_LOCATION).writeByte(0).writeLEB(i + 1);
|
||||
writer.writeLEB(operations.size());
|
||||
operations.newReader(writer::write).readRemaining();
|
||||
}
|
||||
}
|
||||
|
||||
public void end(int size) {
|
||||
if (function == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var writer = generator.getInfoWriter();
|
||||
if (endProgramMarker != null) {
|
||||
var backup = writer.marker();
|
||||
endProgramMarker.rewind();
|
||||
writer.writeInt(offset + size);
|
||||
backup.rewind();
|
||||
}
|
||||
writer.emptyTag();
|
||||
classGen.flushTypes();
|
||||
subprogram = null;
|
||||
endProgramMarker = null;
|
||||
function = null;
|
||||
}
|
||||
|
||||
private DwarfAbbreviation getMethodAbbrev() {
|
||||
if (methodAbbrev == null) {
|
||||
methodAbbrev = generator.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 = generator.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;
|
||||
}
|
||||
|
||||
private DwarfAbbreviation getParameterAbbrev() {
|
||||
if (parameterAbbrev == null) {
|
||||
parameterAbbrev = generator.getInfoWriter().abbreviation(DW_TAG_FORMAL_PARAMETER, false, data -> {
|
||||
data.writeLEB(DW_AT_NAME).writeLEB(DW_FORM_STRP);
|
||||
data.writeLEB(DW_AT_TYPE).writeLEB(DW_FORM_REF4);
|
||||
data.writeLEB(DW_AT_LOCATION).writeLEB(DW_FORM_EXPRLOC);
|
||||
});
|
||||
}
|
||||
return parameterAbbrev;
|
||||
}
|
||||
|
||||
private DwarfAbbreviation getVariableAbbrev() {
|
||||
if (variableAbbrev == null) {
|
||||
variableAbbrev = generator.getInfoWriter().abbreviation(DW_TAG_VARIABLE, false, data -> {
|
||||
data.writeLEB(DW_AT_NAME).writeLEB(DW_FORM_STRP);
|
||||
data.writeLEB(DW_AT_TYPE).writeLEB(DW_FORM_REF4);
|
||||
data.writeLEB(DW_AT_LOCATION).writeLEB(DW_FORM_EXPRLOC);
|
||||
});
|
||||
}
|
||||
return variableAbbrev;
|
||||
}
|
||||
}
|
|
@ -85,7 +85,9 @@ public class WasmGenerator {
|
|||
WasmType type = variable.getType() != null
|
||||
? WasmGeneratorUtil.mapType(variable.getType())
|
||||
: WasmType.INT32;
|
||||
function.add(new WasmLocal(type, variable.getName()));
|
||||
var local = new WasmLocal(type, variable.getName());
|
||||
local.setJavaType(variable.getType());
|
||||
function.add(local);
|
||||
}
|
||||
|
||||
WasmGenerationVisitor visitor = new WasmGenerationVisitor(context, classGenerator, binaryWriter, function,
|
||||
|
|
|
@ -16,12 +16,14 @@
|
|||
package org.teavm.backend.wasm.model;
|
||||
|
||||
import java.util.Objects;
|
||||
import org.teavm.model.util.VariableType;
|
||||
|
||||
public class WasmLocal {
|
||||
WasmFunction function;
|
||||
int index;
|
||||
private String name;
|
||||
private WasmType type;
|
||||
private VariableType javaType;
|
||||
|
||||
public WasmLocal(WasmType type, String name) {
|
||||
Objects.requireNonNull(type);
|
||||
|
@ -57,4 +59,12 @@ public class WasmLocal {
|
|||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public void setJavaType(VariableType javaType) {
|
||||
this.javaType = javaType;
|
||||
}
|
||||
|
||||
public VariableType getJavaType() {
|
||||
return javaType;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,14 +15,6 @@
|
|||
*/
|
||||
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;
|
||||
|
@ -31,14 +23,11 @@ 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.DwarfFunctionGenerator;
|
||||
import org.teavm.backend.wasm.generate.DwarfGenerator;
|
||||
import org.teavm.backend.wasm.model.WasmCustomSection;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmMemorySegment;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
|
@ -67,9 +56,7 @@ public class WasmBinaryRenderer {
|
|||
private Map<String, Integer> functionIndexes = new HashMap<>();
|
||||
private boolean obfuscated;
|
||||
private DwarfGenerator dwarfGenerator;
|
||||
private DwarfClassGenerator dwarfClassGen;
|
||||
private DwarfAbbreviation methodAbbrev;
|
||||
private DwarfAbbreviation functionAbbrev;
|
||||
private DwarfFunctionGenerator dwarfFunctionGen;
|
||||
|
||||
public WasmBinaryRenderer(WasmBinaryWriter output, WasmBinaryVersion version, boolean obfuscated,
|
||||
DwarfGenerator dwarfGenerator, DwarfClassGenerator dwarfClassGen) {
|
||||
|
@ -77,7 +64,7 @@ public class WasmBinaryRenderer {
|
|||
this.version = version;
|
||||
this.obfuscated = obfuscated;
|
||||
this.dwarfGenerator = dwarfGenerator;
|
||||
this.dwarfClassGen = dwarfClassGen;
|
||||
dwarfFunctionGen = dwarfClassGen != null ? new DwarfFunctionGenerator(dwarfClassGen, dwarfGenerator) : null;
|
||||
}
|
||||
|
||||
public void render(WasmModule module) {
|
||||
|
@ -299,35 +286,21 @@ 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;
|
||||
if (dwarfFunctionGen != null) {
|
||||
dwarfFunctionGen.begin(function, offset);
|
||||
|
||||
}
|
||||
|
||||
List<WasmLocal> localVariables = function.getLocalVariables();
|
||||
var localVariables = function.getLocalVariables();
|
||||
int parameterCount = Math.min(function.getParameters().size(), localVariables.size());
|
||||
localVariables = localVariables.subList(parameterCount, localVariables.size());
|
||||
if (localVariables.isEmpty()) {
|
||||
code.writeLEB(0);
|
||||
} else {
|
||||
List<LocalEntry> localEntries = new ArrayList<>();
|
||||
LocalEntry currentEntry = new LocalEntry(localVariables.get(0).getType());
|
||||
var localEntries = new ArrayList<LocalEntry>();
|
||||
var currentEntry = new LocalEntry(localVariables.get(0).getType());
|
||||
for (int i = 1; i < localVariables.size(); ++i) {
|
||||
WasmType type = localVariables.get(i).getType();
|
||||
var type = localVariables.get(i).getType();
|
||||
if (currentEntry.type == type) {
|
||||
currentEntry.count++;
|
||||
} else {
|
||||
|
@ -338,7 +311,7 @@ public class WasmBinaryRenderer {
|
|||
localEntries.add(currentEntry);
|
||||
|
||||
code.writeLEB(localEntries.size());
|
||||
for (LocalEntry entry : localEntries) {
|
||||
for (var entry : localEntries) {
|
||||
code.writeLEB(entry.count);
|
||||
code.writeType(entry.type, version);
|
||||
}
|
||||
|
@ -347,7 +320,7 @@ public class WasmBinaryRenderer {
|
|||
var importIndexes = this.functionIndexes;
|
||||
var visitor = new WasmBinaryRenderingVisitor(code, version, functionIndexes, importIndexes,
|
||||
signatureIndexes, dwarfGenerator, offset);
|
||||
for (WasmExpression part : function.getBody()) {
|
||||
for (var part : function.getBody()) {
|
||||
part.acceptVisitor(visitor);
|
||||
}
|
||||
|
||||
|
@ -357,13 +330,8 @@ public class WasmBinaryRenderer {
|
|||
|
||||
code.writeByte(0x0B);
|
||||
|
||||
if (endProgramMarker != null) {
|
||||
var dwarfWriter = dwarfGenerator.getInfoWriter();
|
||||
var backup = dwarfWriter.marker();
|
||||
endProgramMarker.rewind();
|
||||
dwarfWriter.writeInt(offset + code.getPosition());
|
||||
backup.rewind();
|
||||
dwarfWriter.emptyTag();
|
||||
if (dwarfFunctionGen != null) {
|
||||
dwarfFunctionGen.end(code.getPosition());
|
||||
}
|
||||
|
||||
return code.getData();
|
||||
|
@ -465,27 +433,4 @@ 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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user