mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Wasm: generate DWARF line numbers
Despite generated DWARF sections pass different verifications, they don't work in chrome or wasmtime.
This commit is contained in:
parent
c5011ebf69
commit
f06ba832d7
|
@ -545,7 +545,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
}
|
||||
|
||||
var writer = new WasmBinaryWriter();
|
||||
var renderer = new WasmBinaryRenderer(writer, version, obfuscated);
|
||||
var renderer = new WasmBinaryRenderer(writer, version, obfuscated, dwarfGenerator);
|
||||
renderer.render(module, buildDwarf(dwarfGenerator));
|
||||
|
||||
try (OutputStream output = buildTarget.createResource(outputName)) {
|
||||
|
|
|
@ -22,9 +22,38 @@ public final class DwarfConstants {
|
|||
|
||||
public static final int DW_TAG_COMPILE_UNIT = 0x11;
|
||||
|
||||
public static final int DW_AT_NAME = 0x03;
|
||||
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_PRODUCER = 0x25;
|
||||
|
||||
public static final int DW_CHILDREN_YES = 1;
|
||||
public static final int DW_CHILDREN_NO = 0;
|
||||
|
||||
public static final int DW_LNCT_PATH = 0x1;
|
||||
public static final int DW_LNCT_DIRECTORY_INDEX = 0x2;
|
||||
|
||||
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_STRP = 0x0E;
|
||||
public static final int DW_FORM_SEC_OFFSET = 0x17;
|
||||
public static final int DW_FORM_LINE_STRP = 0x1F;
|
||||
|
||||
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;
|
||||
public static final int DW_LNS_SET_FILE = 0x04;
|
||||
public static final int DW_LNS_SET_COLUMN = 0x05;
|
||||
public static final int DW_LNS_NEGATE_STMT = 0x06;
|
||||
public static final int DW_LNS_SET_BASIC_BLOCK = 0x07;
|
||||
public static final int DW_LNS_CONST_ADD_PC = 0x08;
|
||||
public static final int DW_LNS_FIXED_ADVANCE_PC = 0x09;
|
||||
public static final int DW_LNS_SET_PROLOGUE_END = 0x0A;
|
||||
public static final int DW_LNS_SET_EPILOGUE_BEGIN = 0x0B;
|
||||
public static final int DW_LNS_SET_ISA = 0x0C;
|
||||
|
||||
private DwarfConstants() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,15 @@ public class DwarfInfoWriter {
|
|||
return this;
|
||||
}
|
||||
|
||||
public DwarfInfoWriter skip(int count) {
|
||||
output.skip(count);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Marker marker() {
|
||||
return output.marker();
|
||||
}
|
||||
|
||||
public DwarfAbbreviation abbreviation(int tag, boolean hasChildren, Consumer<Blob> blob) {
|
||||
var abbr = new DwarfAbbreviation(tag, hasChildren, blob);
|
||||
abbreviations.add(abbr);
|
||||
|
|
|
@ -100,12 +100,30 @@ public class Blob {
|
|||
var buffer = this.buffer;
|
||||
while ((value & 0x7F) != value) {
|
||||
buffer[ptr++] = (byte) ((value & 0x7F) | 0x80);
|
||||
value >>= 7;
|
||||
value >>>= 7;
|
||||
}
|
||||
buffer[ptr++] = (byte) (value & 0x7F);
|
||||
return write(buffer, 0, ptr);
|
||||
}
|
||||
|
||||
public Blob writeSLEB(int value) {
|
||||
var ptr = 0;
|
||||
var buffer = this.buffer;
|
||||
var sign = value >>> 31;
|
||||
while (true) {
|
||||
var digit = value & 0x7F;
|
||||
value >>= 7;
|
||||
var more = value != 0 && value != -1 || digit >> 6 != sign;
|
||||
if (more) {
|
||||
buffer[ptr++] = (byte) (digit | 0x80);
|
||||
} else {
|
||||
buffer[ptr++] = (byte) digit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return write(buffer, 0, ptr);
|
||||
}
|
||||
|
||||
private void nextChunkIfNeeded() {
|
||||
if (posInChunk < currentChunk.length) {
|
||||
return;
|
||||
|
@ -127,6 +145,10 @@ public class Blob {
|
|||
return new BlobReader(this, consumer);
|
||||
}
|
||||
|
||||
public BinaryDataConsumer writer() {
|
||||
return this::write;
|
||||
}
|
||||
|
||||
public Marker marker() {
|
||||
return new Marker(this, chunkIndex, posInChunk, ptr);
|
||||
}
|
||||
|
|
|
@ -16,14 +16,14 @@
|
|||
package org.teavm.backend.wasm.dwarf.blob;
|
||||
|
||||
public class BlobReader {
|
||||
private Blob output;
|
||||
private Blob blob;
|
||||
private BinaryDataConsumer consumer;
|
||||
private int ptr;
|
||||
private int currentChunk;
|
||||
private int offsetInChunk;
|
||||
|
||||
BlobReader(Blob output, BinaryDataConsumer consumer) {
|
||||
this.output = output;
|
||||
BlobReader(Blob blob, BinaryDataConsumer consumer) {
|
||||
this.blob = blob;
|
||||
this.consumer = consumer;
|
||||
}
|
||||
|
||||
|
@ -31,8 +31,12 @@ public class BlobReader {
|
|||
return ptr;
|
||||
}
|
||||
|
||||
public void readRemaining() {
|
||||
advance(blob.size());
|
||||
}
|
||||
|
||||
public void advance(int to) {
|
||||
if (to < ptr || to > output.size()) {
|
||||
if (to < ptr || to > blob.size()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (to == ptr) {
|
||||
|
@ -43,7 +47,7 @@ public class BlobReader {
|
|||
var currentChunk = this.currentChunk;
|
||||
var offsetInChunk = this.offsetInChunk;
|
||||
while (ptr < to) {
|
||||
var chunk = output.chunkAt(currentChunk);
|
||||
var chunk = blob.chunkAt(currentChunk);
|
||||
var limit = Math.min(ptr + chunk.length, to);
|
||||
var bytesToWrite = limit - ptr;
|
||||
consumer.accept(chunk, offsetInChunk, offsetInChunk + bytesToWrite);
|
||||
|
|
|
@ -40,4 +40,8 @@ public class Marker {
|
|||
posInChunk = blob.posInChunk;
|
||||
ptr = blob.ptr;
|
||||
}
|
||||
|
||||
public int ptr() {
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,19 +18,26 @@ package org.teavm.backend.wasm.generate;
|
|||
import static org.teavm.backend.wasm.dwarf.DwarfConstants.DWARF_VERSION;
|
||||
import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_TAG_COMPILE_UNIT;
|
||||
import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_UT_COMPILE;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import org.teavm.backend.wasm.dwarf.DwarfConstants;
|
||||
import org.teavm.backend.wasm.dwarf.DwarfInfoWriter;
|
||||
import org.teavm.backend.wasm.dwarf.DwarfPlaceholder;
|
||||
import org.teavm.backend.wasm.dwarf.blob.Blob;
|
||||
import org.teavm.backend.wasm.dwarf.blob.Marker;
|
||||
import org.teavm.backend.wasm.model.WasmCustomSection;
|
||||
|
||||
public class DwarfGenerator {
|
||||
private DwarfInfoWriter infoWriter = new DwarfInfoWriter();
|
||||
private DwarfPlaceholder endOfSection;
|
||||
private DwarfStrings strings = new DwarfStrings();
|
||||
private DwarfStrings lineStrings = new DwarfStrings();
|
||||
private DwarfLinesGenerator lines = new DwarfLinesGenerator(lineStrings);
|
||||
private Marker highPcMarker;
|
||||
|
||||
public void begin() {
|
||||
endOfSection = infoWriter.placeholder(4);
|
||||
lines.begin();
|
||||
emitUnitHeader();
|
||||
compilationUnit();
|
||||
}
|
||||
|
@ -56,28 +63,60 @@ public class DwarfGenerator {
|
|||
}
|
||||
|
||||
private void compilationUnit() {
|
||||
infoWriter.tag(infoWriter.abbreviation(DW_TAG_COMPILE_UNIT, true, data -> { }));
|
||||
infoWriter.tag(infoWriter.abbreviation(DW_TAG_COMPILE_UNIT, true, data -> {
|
||||
data.writeLEB(DwarfConstants.DW_AT_PRODUCER).writeLEB(DwarfConstants.DW_FORM_STRP);
|
||||
data.writeLEB(DwarfConstants.DW_AT_NAME).writeLEB(DwarfConstants.DW_FORM_STRP);
|
||||
data.writeLEB(DwarfConstants.DW_AT_STMT_LIST).writeLEB(DwarfConstants.DW_FORM_SEC_OFFSET);
|
||||
data.writeLEB(DwarfConstants.DW_AT_LOW_PC).writeLEB(DwarfConstants.DW_FORM_ADDR);
|
||||
data.writeLEB(DwarfConstants.DW_AT_HIGH_PC).writeLEB(DwarfConstants.DW_FORM_ADDR);
|
||||
}));
|
||||
infoWriter.writeInt(strings.stringRef("TeaVM"));
|
||||
infoWriter.writeInt(strings.stringRef("classes.wasm"));
|
||||
infoWriter.writeInt(0);
|
||||
infoWriter.writeInt(0);
|
||||
highPcMarker = infoWriter.marker();
|
||||
infoWriter.skip(4);
|
||||
}
|
||||
|
||||
public void end() {
|
||||
closeTag(); // compilation unit
|
||||
infoWriter.mark(endOfSection);
|
||||
lines.end();
|
||||
}
|
||||
|
||||
private void closeTag() {
|
||||
infoWriter.writeByte(0);
|
||||
}
|
||||
|
||||
public void setCodeSize(int codeSize) {
|
||||
highPcMarker.rewind();
|
||||
infoWriter.writeInt(codeSize);
|
||||
}
|
||||
|
||||
public Collection<? extends WasmCustomSection> createSections() {
|
||||
var sections = new ArrayList<WasmCustomSection>();
|
||||
|
||||
var abbreviations = new Blob();
|
||||
infoWriter.buildAbbreviations(abbreviations);
|
||||
sections.add(new WasmCustomSection(".debug_abbrev", abbreviations.toArray()));
|
||||
|
||||
var info = new Blob();
|
||||
infoWriter.build(info);
|
||||
sections.add(new WasmCustomSection(".debug_info", info.toArray()));
|
||||
|
||||
return Arrays.asList(
|
||||
new WasmCustomSection(".debug_abbrev", abbreviations.toArray()),
|
||||
new WasmCustomSection(".debug_info", info.toArray())
|
||||
);
|
||||
if (strings.blob.size() > 0) {
|
||||
sections.add(new WasmCustomSection(".debug_str", strings.blob.toArray()));
|
||||
}
|
||||
if (lineStrings.blob.size() > 0) {
|
||||
sections.add(new WasmCustomSection(".debug_line_str", lineStrings.blob.toArray()));
|
||||
}
|
||||
|
||||
sections.add(new WasmCustomSection(".debug_line", lines.blob.toArray()));
|
||||
|
||||
return sections;
|
||||
}
|
||||
|
||||
public void lineNumber(int address, String fileName, int lineNumber) {
|
||||
lines.lineNumber(address, fileName, lineNumber);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* 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_FORM_DATA2;
|
||||
import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_FORM_LINE_STRP;
|
||||
import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_LNCT_DIRECTORY_INDEX;
|
||||
import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_LNCT_PATH;
|
||||
import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_LNS_ADVANCE_LINE;
|
||||
import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_LNS_ADVANCE_PC;
|
||||
import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_LNS_COPY;
|
||||
import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_LNS_SET_FILE;
|
||||
import com.carrotsearch.hppc.ObjectIntHashMap;
|
||||
import com.carrotsearch.hppc.ObjectIntMap;
|
||||
import org.teavm.backend.wasm.dwarf.blob.Blob;
|
||||
import org.teavm.backend.wasm.dwarf.blob.Marker;
|
||||
|
||||
class DwarfLinesGenerator {
|
||||
private static final int MIN_INSN_LEN = 1;
|
||||
private static final int LINE_BASE = -3;
|
||||
private static final int LINE_RANGE = 8;
|
||||
private static final int OPCODE_BASE = 13;
|
||||
|
||||
Blob blob = new Blob();
|
||||
private DwarfStrings strings;
|
||||
private Blob instructionsBlob = new Blob();
|
||||
private Marker unitLengthMarker;
|
||||
private Marker headerLengthMarker;
|
||||
private Blob filesBlob = new Blob();
|
||||
private ObjectIntMap<String> fileIndexes = new ObjectIntHashMap<>();
|
||||
private Blob dirsBlob = new Blob();
|
||||
private ObjectIntMap<String> dirIndexes = new ObjectIntHashMap<>();
|
||||
private int address;
|
||||
private int file = 1;
|
||||
private int line = 1;
|
||||
|
||||
DwarfLinesGenerator(DwarfStrings strings) {
|
||||
this.strings = strings;
|
||||
}
|
||||
|
||||
void begin() {
|
||||
emitLinesHeader();
|
||||
}
|
||||
|
||||
private void emitLinesHeader() {
|
||||
// length
|
||||
unitLengthMarker = blob.marker();
|
||||
blob.skip(4);
|
||||
|
||||
// version
|
||||
blob.writeShort(5);
|
||||
|
||||
// address_size
|
||||
blob.writeByte(4);
|
||||
|
||||
// segment_selector_size
|
||||
blob.writeByte(0);
|
||||
|
||||
// header_length
|
||||
headerLengthMarker = blob.marker();
|
||||
blob.skip(4);
|
||||
|
||||
// minimum_instruction_length
|
||||
blob.writeByte(MIN_INSN_LEN);
|
||||
|
||||
// maximum_operations_per_instruction
|
||||
blob.writeByte(1);
|
||||
|
||||
// default_is_stmt
|
||||
blob.writeByte(1);
|
||||
|
||||
blob.writeByte(LINE_BASE).writeByte(LINE_RANGE).writeByte(OPCODE_BASE);
|
||||
|
||||
// standard_opcode_lengths
|
||||
|
||||
blob.writeByte(0); // DW_LNS_COPY
|
||||
blob.writeByte(1); // DW_LNS_ADVANCE_PC
|
||||
blob.writeByte(1); // DW_LNS_ADVANCE_LINE
|
||||
blob.writeByte(1); // DW_LNS_SET_FILE
|
||||
blob.writeByte(1); // DW_LNS_SET_COLUMN
|
||||
blob.writeByte(0); // DW_LNS_NEGATE_STMT
|
||||
blob.writeByte(0); // DW_LNS_SET_BASIC_BLOCK
|
||||
blob.writeByte(0); // DW_LNS_CONST_ADD_PC
|
||||
blob.writeByte(1); // DW_LNS_FIXED_ADVANCE_PC
|
||||
blob.writeByte(0); // DW_LNS_SET_PROLOGUE_END
|
||||
blob.writeByte(0); // DW_LNS_SET_EPILOGUE_BEGIN
|
||||
blob.writeByte(1); // DW_LNS_SET_ISA
|
||||
}
|
||||
|
||||
void end() {
|
||||
emitDirsAndFiles();
|
||||
finishHeader();
|
||||
|
||||
instructionsBlob.newReader(blob.writer()).readRemaining();
|
||||
|
||||
var length = blob.ptr() - unitLengthMarker.ptr() - 4;
|
||||
unitLengthMarker.rewind();
|
||||
blob.writeInt(length);
|
||||
}
|
||||
|
||||
private void emitDirsAndFiles() {
|
||||
blob.writeByte(1); // directory_entry_format_count
|
||||
blob.writeByte(DW_LNCT_PATH);
|
||||
blob.writeByte(DW_FORM_LINE_STRP);
|
||||
blob.writeLEB(dirIndexes.size());
|
||||
dirsBlob.newReader(blob.writer()).readRemaining();
|
||||
|
||||
blob.writeByte(2); // file_name_entry_format_count
|
||||
blob.writeByte(DW_LNCT_DIRECTORY_INDEX);
|
||||
blob.writeByte(DW_FORM_DATA2);
|
||||
blob.writeByte(DW_LNCT_PATH);
|
||||
blob.writeByte(DW_FORM_LINE_STRP);
|
||||
blob.writeLEB(fileIndexes.size());
|
||||
filesBlob.newReader(blob.writer()).readRemaining();
|
||||
}
|
||||
|
||||
private void finishHeader() {
|
||||
var marker = blob.marker();
|
||||
var headerLength = blob.ptr() - headerLengthMarker.ptr() - 4;
|
||||
headerLengthMarker.rewind();
|
||||
blob.writeInt(headerLength);
|
||||
marker.rewind();
|
||||
}
|
||||
|
||||
private int fileRef(String path) {
|
||||
var ref = fileIndexes.getOrDefault(path, -1);
|
||||
if (ref < 0) {
|
||||
var nameIndex = path.lastIndexOf('/') + 1;
|
||||
var name = path.substring(nameIndex);
|
||||
var dir = path.substring(0, Math.max(0, nameIndex - 1));
|
||||
|
||||
var dirPtr = dirRef(dir);
|
||||
ref = fileIndexes.size();
|
||||
fileIndexes.put(path, ref);
|
||||
|
||||
filesBlob.writeShort(dirPtr);
|
||||
filesBlob.writeInt(strings.stringRef(name));
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
private int dirRef(String path) {
|
||||
var ref = dirIndexes.getOrDefault(path, -1);
|
||||
if (ref < 0) {
|
||||
ref = dirIndexes.size();
|
||||
dirIndexes.put(path, ref);
|
||||
dirsBlob.writeInt(strings.stringRef(path));
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
void lineNumber(int address, String file, int line) {
|
||||
var changed = false;
|
||||
var fileRef = fileRef(file);
|
||||
if (fileRef != this.file) {
|
||||
this.file = fileRef;
|
||||
instructionsBlob.writeByte(DW_LNS_SET_FILE);
|
||||
instructionsBlob.writeLEB(fileRef);
|
||||
changed = true;
|
||||
}
|
||||
if (address != this.address || line != this.line) {
|
||||
int lineIncrement = line - this.line;
|
||||
int addressIncrement = address - this.address;
|
||||
if (!tryEmitSpecial(lineIncrement, addressIncrement)) {
|
||||
if (lineIncrement != 0) {
|
||||
instructionsBlob.writeByte(DW_LNS_ADVANCE_LINE);
|
||||
instructionsBlob.writeSLEB(lineIncrement);
|
||||
}
|
||||
if (addressIncrement != 0) {
|
||||
instructionsBlob.writeByte(DW_LNS_ADVANCE_PC);
|
||||
instructionsBlob.writeSLEB(addressIncrement);
|
||||
}
|
||||
}
|
||||
changed = true;
|
||||
this.line = line;
|
||||
this.address = address;
|
||||
}
|
||||
if (changed) {
|
||||
instructionsBlob.writeByte(DW_LNS_COPY);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean tryEmitSpecial(int lineIncrement, int addressIncrement) {
|
||||
if (lineIncrement < LINE_BASE || lineIncrement >= LINE_BASE + LINE_RANGE) {
|
||||
return false;
|
||||
}
|
||||
int opcode = lineIncrement - LINE_BASE + (LINE_RANGE * addressIncrement) + OPCODE_BASE;
|
||||
if (opcode <= OPCODE_BASE || opcode > 255) {
|
||||
return false;
|
||||
}
|
||||
instructionsBlob.writeByte(opcode);
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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 com.carrotsearch.hppc.ObjectIntHashMap;
|
||||
import com.carrotsearch.hppc.ObjectIntMap;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import org.teavm.backend.wasm.dwarf.blob.Blob;
|
||||
|
||||
class DwarfStrings {
|
||||
final Blob blob = new Blob();
|
||||
private ObjectIntMap<String> offsets = new ObjectIntHashMap<>();
|
||||
|
||||
int stringRef(String s) {
|
||||
int ptr = offsets.getOrDefault(s, -1);
|
||||
if (ptr < 0) {
|
||||
ptr = blob.size();
|
||||
offsets.put(s, ptr);
|
||||
var bytes = s.getBytes(StandardCharsets.UTF_8);
|
||||
blob.write(bytes);
|
||||
blob.writeByte(0);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
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;
|
||||
|
@ -53,11 +54,14 @@ public class WasmBinaryRenderer {
|
|||
private Map<WasmSignature, Integer> signatureIndexes = new HashMap<>();
|
||||
private Map<String, Integer> functionIndexes = new HashMap<>();
|
||||
private boolean obfuscated;
|
||||
private DwarfGenerator dwarfGenerator;
|
||||
|
||||
public WasmBinaryRenderer(WasmBinaryWriter output, WasmBinaryVersion version, boolean obfuscated) {
|
||||
public WasmBinaryRenderer(WasmBinaryWriter output, WasmBinaryVersion version, boolean obfuscated,
|
||||
DwarfGenerator dwarfGenerator) {
|
||||
this.output = output;
|
||||
this.version = version;
|
||||
this.obfuscated = obfuscated;
|
||||
this.dwarfGenerator = dwarfGenerator;
|
||||
}
|
||||
|
||||
public void render(WasmModule module) {
|
||||
|
@ -256,24 +260,28 @@ public class WasmBinaryRenderer {
|
|||
}
|
||||
|
||||
private void renderCode(WasmModule module) {
|
||||
WasmBinaryWriter section = new WasmBinaryWriter();
|
||||
var section = new WasmBinaryWriter();
|
||||
|
||||
List<WasmFunction> functions = module.getFunctions().values().stream()
|
||||
var functions = module.getFunctions().values().stream()
|
||||
.filter(function -> function.getImportName() == null)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
section.writeLEB(functions.size());
|
||||
for (WasmFunction function : functions) {
|
||||
byte[] body = renderFunction(function);
|
||||
for (var function : functions) {
|
||||
var body = renderFunction(function, section.getPosition());
|
||||
section.writeLEB(body.length);
|
||||
section.writeBytes(body);
|
||||
}
|
||||
|
||||
if (dwarfGenerator != null) {
|
||||
dwarfGenerator.setCodeSize(section.getPosition());
|
||||
}
|
||||
|
||||
writeSection(SECTION_CODE, "code", section.getData());
|
||||
}
|
||||
|
||||
private byte[] renderFunction(WasmFunction function) {
|
||||
WasmBinaryWriter code = new WasmBinaryWriter();
|
||||
private byte[] renderFunction(WasmFunction function, int offset) {
|
||||
var code = new WasmBinaryWriter();
|
||||
|
||||
List<WasmLocal> localVariables = function.getLocalVariables();
|
||||
int parameterCount = Math.min(function.getParameters().size(), localVariables.size());
|
||||
|
@ -301,9 +309,9 @@ public class WasmBinaryRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
Map<String, Integer> importIndexes = this.functionIndexes;
|
||||
WasmBinaryRenderingVisitor visitor = new WasmBinaryRenderingVisitor(code, version, functionIndexes,
|
||||
importIndexes, signatureIndexes);
|
||||
var importIndexes = this.functionIndexes;
|
||||
var visitor = new WasmBinaryRenderingVisitor(code, version, functionIndexes, importIndexes,
|
||||
signatureIndexes, dwarfGenerator, offset);
|
||||
for (WasmExpression part : function.getBody()) {
|
||||
part.acceptVisitor(visitor);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.backend.wasm.render;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.teavm.backend.wasm.generate.DwarfGenerator;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||
|
@ -57,16 +58,21 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
private Map<String, Integer> functionIndexes;
|
||||
private Map<String, Integer> importedIndexes;
|
||||
private Map<WasmSignature, Integer> signatureIndexes;
|
||||
private DwarfGenerator dwarfGenerator;
|
||||
private int addressOffset;
|
||||
private int depth;
|
||||
private Map<WasmBlock, Integer> blockDepths = new HashMap<>();
|
||||
|
||||
WasmBinaryRenderingVisitor(WasmBinaryWriter writer, WasmBinaryVersion version, Map<String, Integer> functionIndexes,
|
||||
Map<String, Integer> importedIndexes, Map<WasmSignature, Integer> signatureIndexes) {
|
||||
Map<String, Integer> importedIndexes, Map<WasmSignature, Integer> signatureIndexes,
|
||||
DwarfGenerator dwarfGenerator, int addressOffset) {
|
||||
this.writer = writer;
|
||||
this.version = version;
|
||||
this.functionIndexes = functionIndexes;
|
||||
this.importedIndexes = importedIndexes;
|
||||
this.signatureIndexes = signatureIndexes;
|
||||
this.dwarfGenerator = dwarfGenerator;
|
||||
this.addressOffset = addressOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -95,6 +101,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
}
|
||||
expression.getCondition().acceptVisitor(this);
|
||||
|
||||
emitLocation(expression);
|
||||
writer.writeByte(0x0D);
|
||||
|
||||
writeLabel(expression.getTarget());
|
||||
|
@ -106,6 +113,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
expression.getResult().acceptVisitor(this);
|
||||
}
|
||||
|
||||
emitLocation(expression);
|
||||
writer.writeByte(0x0C);
|
||||
|
||||
writeLabel(expression.getTarget());
|
||||
|
@ -115,6 +123,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
public void visit(WasmSwitch expression) {
|
||||
expression.getSelector().acceptVisitor(this);
|
||||
|
||||
emitLocation(expression);
|
||||
writer.writeByte(0x0E);
|
||||
|
||||
writer.writeLEB(expression.getTargets().size());
|
||||
|
@ -132,6 +141,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
@Override
|
||||
public void visit(WasmConditional expression) {
|
||||
expression.getCondition().acceptVisitor(this);
|
||||
emitLocation(expression);
|
||||
writer.writeByte(0x04);
|
||||
writeBlockType(expression.getType());
|
||||
|
||||
|
@ -160,40 +170,47 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
if (expression.getValue() != null) {
|
||||
expression.getValue().acceptVisitor(this);
|
||||
}
|
||||
emitLocation(expression);
|
||||
writer.writeByte(0x0F);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmUnreachable expression) {
|
||||
emitLocation(expression);
|
||||
writer.writeByte(0x0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmInt32Constant expression) {
|
||||
emitLocation(expression);
|
||||
writer.writeByte(0x41);
|
||||
writer.writeSignedLEB(expression.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmInt64Constant expression) {
|
||||
emitLocation(expression);
|
||||
writer.writeByte(0x42);
|
||||
writer.writeSignedLEB(expression.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFloat32Constant expression) {
|
||||
emitLocation(expression);
|
||||
writer.writeByte(0x43);
|
||||
writer.writeFixed(Float.floatToRawIntBits(expression.getValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFloat64Constant expression) {
|
||||
emitLocation(expression);
|
||||
writer.writeByte(0x44);
|
||||
writer.writeFixed(Double.doubleToRawLongBits(expression.getValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmGetLocal expression) {
|
||||
emitLocation(expression);
|
||||
writer.writeByte(0x20);
|
||||
writer.writeLEB(expression.getLocal().getIndex());
|
||||
}
|
||||
|
@ -201,6 +218,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
@Override
|
||||
public void visit(WasmSetLocal expression) {
|
||||
expression.getValue().acceptVisitor(this);
|
||||
emitLocation(expression);
|
||||
writer.writeByte(0x21);
|
||||
writer.writeLEB(expression.getLocal().getIndex());
|
||||
}
|
||||
|
@ -209,6 +227,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
public void visit(WasmIntBinary expression) {
|
||||
expression.getFirst().acceptVisitor(this);
|
||||
expression.getSecond().acceptVisitor(this);
|
||||
emitLocation(expression);
|
||||
render0xD(expression);
|
||||
}
|
||||
|
||||
|
@ -379,6 +398,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
public void visit(WasmFloatBinary expression) {
|
||||
expression.getFirst().acceptVisitor(this);
|
||||
expression.getSecond().acceptVisitor(this);
|
||||
emitLocation(expression);
|
||||
render0xD(expression);
|
||||
}
|
||||
|
||||
|
@ -503,6 +523,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
@Override
|
||||
public void visit(WasmFloatUnary expression) {
|
||||
expression.getOperand().acceptVisitor(this);
|
||||
emitLocation(expression);
|
||||
render0xD(expression);
|
||||
}
|
||||
|
||||
|
@ -570,6 +591,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
@Override
|
||||
public void visit(WasmConversion expression) {
|
||||
expression.getOperand().acceptVisitor(this);
|
||||
emitLocation(expression);
|
||||
switch (expression.getSourceType()) {
|
||||
case INT32:
|
||||
switch (expression.getTargetType()) {
|
||||
|
@ -658,6 +680,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
Integer functionIndex = !expression.isImported()
|
||||
? functionIndexes.get(expression.getFunctionName())
|
||||
: importedIndexes.get(expression.getFunctionName());
|
||||
emitLocation(expression);
|
||||
if (functionIndex == null) {
|
||||
writer.writeByte(0x00);
|
||||
return;
|
||||
|
@ -688,12 +711,14 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
@Override
|
||||
public void visit(WasmDrop expression) {
|
||||
expression.getOperand().acceptVisitor(this);
|
||||
emitLocation(expression);
|
||||
writer.writeByte(0x1A);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmLoadInt32 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
emitLocation(expression);
|
||||
switch (expression.getConvertFrom()) {
|
||||
case INT8:
|
||||
writer.writeByte(0x2C);
|
||||
|
@ -718,6 +743,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
@Override
|
||||
public void visit(WasmLoadInt64 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
emitLocation(expression);
|
||||
switch (expression.getConvertFrom()) {
|
||||
case INT8:
|
||||
writer.writeByte(0x30);
|
||||
|
@ -748,6 +774,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
@Override
|
||||
public void visit(WasmLoadFloat32 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
emitLocation(expression);
|
||||
writer.writeByte(0x2A);
|
||||
writer.writeByte(alignment(expression.getAlignment()));
|
||||
writer.writeLEB(expression.getOffset());
|
||||
|
@ -756,6 +783,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
@Override
|
||||
public void visit(WasmLoadFloat64 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
emitLocation(expression);
|
||||
writer.writeByte(0x2B);
|
||||
writer.writeByte(alignment(expression.getAlignment()));
|
||||
writer.writeLEB(expression.getOffset());
|
||||
|
@ -765,6 +793,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
public void visit(WasmStoreInt32 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
expression.getValue().acceptVisitor(this);
|
||||
emitLocation(expression);
|
||||
switch (expression.getConvertTo()) {
|
||||
case INT8:
|
||||
case UINT8:
|
||||
|
@ -786,6 +815,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
public void visit(WasmStoreInt64 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
expression.getValue().acceptVisitor(this);
|
||||
emitLocation(expression);
|
||||
switch (expression.getConvertTo()) {
|
||||
case INT8:
|
||||
case UINT8:
|
||||
|
@ -811,6 +841,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
public void visit(WasmStoreFloat32 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
expression.getValue().acceptVisitor(this);
|
||||
emitLocation(expression);
|
||||
writer.writeByte(0x38);
|
||||
writer.writeByte(alignment(expression.getAlignment()));
|
||||
writer.writeLEB(expression.getOffset());
|
||||
|
@ -820,6 +851,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
public void visit(WasmStoreFloat64 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
expression.getValue().acceptVisitor(this);
|
||||
emitLocation(expression);
|
||||
writer.writeByte(0x39);
|
||||
writer.writeByte(alignment(expression.getAlignment()));
|
||||
writer.writeLEB(expression.getOffset());
|
||||
|
@ -828,6 +860,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
@Override
|
||||
public void visit(WasmMemoryGrow expression) {
|
||||
expression.getAmount().acceptVisitor(this);
|
||||
emitLocation(expression);
|
||||
writer.writeByte(0x40);
|
||||
writer.writeByte(0);
|
||||
}
|
||||
|
@ -840,4 +873,12 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
int blockDepth = blockDepths.get(target);
|
||||
writer.writeLEB(depth - blockDepth);
|
||||
}
|
||||
|
||||
private void emitLocation(WasmExpression expression) {
|
||||
if (dwarfGenerator == null || expression.getLocation() == null) {
|
||||
return;
|
||||
}
|
||||
dwarfGenerator.lineNumber(writer.getPosition() + addressOffset, expression.getLocation().getFileName(),
|
||||
expression.getLocation().getLine());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user