Wasm: generate debugging information for own debugger

This commit is contained in:
Alexey Andreev 2022-11-24 17:23:32 +01:00
parent 7e95e935d1
commit 56929b2085
33 changed files with 773 additions and 34 deletions

View File

@ -40,6 +40,7 @@ import org.teavm.backend.lowlevel.generate.NameProvider;
import org.teavm.backend.lowlevel.generate.NameProviderWithSpecialNames;
import org.teavm.backend.lowlevel.transform.CoroutineTransformation;
import org.teavm.backend.wasm.binary.BinaryWriter;
import org.teavm.backend.wasm.debug.DebugInfoBuilder;
import org.teavm.backend.wasm.generate.DwarfClassGenerator;
import org.teavm.backend.wasm.generate.DwarfGenerator;
import org.teavm.backend.wasm.generate.WasmClassGenerator;
@ -550,8 +551,10 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
}
var writer = new WasmBinaryWriter();
var renderer = new WasmBinaryRenderer(writer, version, obfuscated, dwarfGenerator, dwarfClassGen);
renderer.render(module, buildDwarf(dwarfGenerator, dwarfClassGen));
var debugBuilder = debugging ? new DebugInfoBuilder() : null;
var renderer = new WasmBinaryRenderer(writer, version, obfuscated, dwarfGenerator, dwarfClassGen,
debugBuilder.lines());
renderer.render(module, buildDebug(dwarfGenerator, dwarfClassGen, debugBuilder));
try (OutputStream output = buildTarget.createResource(outputName)) {
output.write(writer.getData());
@ -570,15 +573,24 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
}
}
private Supplier<Collection<? extends WasmCustomSection>> buildDwarf(DwarfGenerator generator,
DwarfClassGenerator classGen) {
if (generator == null) {
private Supplier<Collection<? extends WasmCustomSection>> buildDebug(DwarfGenerator generator,
DwarfClassGenerator classGen, DebugInfoBuilder debugBuilder) {
if (generator == null || debugBuilder == null) {
return null;
}
return () -> {
classGen.write();
generator.end();
return generator.createSections();
var sections = new ArrayList<WasmCustomSection>();
if (classGen != null) {
classGen.write();
}
if (generator != null) {
generator.end();
sections.addAll(generator.createSections());
}
if (debugBuilder != null) {
sections.addAll(debugBuilder.build());
}
return sections;
};
}

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.backend.wasm.dwarf.blob;
package org.teavm.backend.wasm.blob;
public interface BinaryDataConsumer {
void accept(byte[] data, int offset, int limit);

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.backend.wasm.dwarf.blob;
package org.teavm.backend.wasm.blob;
import java.util.ArrayList;
import java.util.List;

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.backend.wasm.dwarf.blob;
package org.teavm.backend.wasm.blob;
public class BlobReader {
private Blob blob;

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.backend.wasm.dwarf.blob;
package org.teavm.backend.wasm.blob;
public class Marker {
private Blob blob;

View File

@ -0,0 +1,20 @@
/*
* 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.debug;
public interface DebugClasses {
int classPtr(String className);
}

View File

@ -0,0 +1,52 @@
/*
* 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.debug;
import com.carrotsearch.hppc.ObjectIntHashMap;
import com.carrotsearch.hppc.ObjectIntMap;
public class DebugClassesBuilder extends DebugSectionBuilder implements DebugClasses {
private DebugPackages packages;
private DebugStrings strings;
private ObjectIntMap<String> classes = new ObjectIntHashMap<>();
public DebugClassesBuilder(DebugPackages packages, DebugStrings strings) {
this.packages = packages;
this.strings = strings;
}
@Override
public int classPtr(String className) {
var result = classes.getOrDefault(className, -1);
if (result < 0) {
result = classes.size();
classes.put(className, result);
var packagePtr = 0;
var index = 0;
while (true) {
var next = className.indexOf('.', index);
if (next < 0) {
break;
}
packagePtr = packages.packagePtr(packagePtr, className.substring(index, next));
index = next + 1;
}
blob.writeLEB(packagePtr);
blob.writeLEB(strings.stringPtr(className.substring(index)));
}
return result;
}
}

View File

@ -0,0 +1,28 @@
/*
* 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.debug;
public final class DebugConstants {
private DebugConstants() {
}
public static final int LOC_START = 0;
public static final int LOC_END = 1;
public static final int LOC_LINE = 2;
public static final int LOC_FILE = 3;
public static final int LOC_PTR = 4;
public static final int LOC_USER = 10;
}

View File

@ -0,0 +1,20 @@
/*
* 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.debug;
public interface DebugFiles {
int filePtr(String fileName);
}

View File

@ -0,0 +1,90 @@
/*
* 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.debug;
import com.carrotsearch.hppc.ObjectIntHashMap;
import com.carrotsearch.hppc.ObjectIntMap;
import java.util.Objects;
public class DebugFilesBuilder extends DebugSectionBuilder implements DebugFiles {
private DebugStrings strings;
private ObjectIntMap<FileData> fileMap = new ObjectIntHashMap<>();
public DebugFilesBuilder(DebugStrings strings) {
this.strings = strings;
}
@Override
public int filePtr(String fileName) {
var index = 0;
var current = 0;
while (true) {
var next = fileName.indexOf('/', index);
if (next < 0) {
break;
}
var dirName = fileName.substring(index, next);
current = filePtr(current, dirName);
index = next + 1;
}
return filePtr(current, fileName.substring(index));
}
private int filePtr(int parent, String fileName) {
var data = new FileData(parent, fileName);
var ptr = fileMap.getOrDefault(data, 0);
if (ptr == 0) {
ptr = fileMap.size() + 1;
fileMap.put(data, ptr);
blob.writeLEB(parent);
var extensionIndex = fileName.lastIndexOf('.');
if (extensionIndex < 0) {
blob.writeLEB(strings.stringPtr(fileName) << 1);
} else {
blob.writeLEB(1 | (strings.stringPtr(fileName.substring(0, extensionIndex)) << 1));
blob.writeLEB(strings.stringPtr(fileName.substring(extensionIndex + 1)));
}
}
return ptr;
}
private static class FileData {
private final int parent;
private final String name;
FileData(int parent, String name) {
this.parent = parent;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
FileData fileData = (FileData) o;
return parent == fileData.parent && name.equals(fileData.name);
}
@Override
public int hashCode() {
return Objects.hash(parent, name);
}
}
}

View File

@ -0,0 +1,80 @@
/*
* 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.debug;
import java.util.ArrayList;
import java.util.List;
import org.teavm.backend.wasm.model.WasmCustomSection;
public class DebugInfoBuilder {
private DebugStringsBuilder strings;
private DebugFilesBuilder files;
private DebugPackagesBuilder packages;
private DebugClassesBuilder classes;
private DebugMethodsBuilder methods;
private DebugLinesBuilder lines;
public DebugInfoBuilder() {
strings = new DebugStringsBuilder();
files = new DebugFilesBuilder(strings);
packages = new DebugPackagesBuilder(strings);
classes = new DebugClassesBuilder(packages, strings);
methods = new DebugMethodsBuilder(classes, strings);
lines = new DebugLinesBuilder(files, methods);
}
public DebugStrings strings() {
return strings;
}
public DebugFiles files() {
return files;
}
public DebugPackages packages() {
return packages;
}
public DebugClasses classes() {
return classes;
}
public DebugMethodsBuilder methods() {
return methods;
}
public DebugLinesBuilder lines() {
return lines;
}
public List<WasmCustomSection> build() {
var result = new ArrayList<WasmCustomSection>();
addSection(result, "teavm_str", strings);
addSection(result, "teavm_file", files);
addSection(result, "teavm_pkg", packages);
addSection(result, "teavm_classes", classes);
addSection(result, "teavm_methods", methods);
addSection(result, "teavm_line", lines);
return result;
}
private void addSection(List<WasmCustomSection> sections, String name, DebugSectionBuilder builder) {
if (builder.isEmpty()) {
return;
}
sections.add(new WasmCustomSection(name, builder.build()));
}
}

View File

@ -0,0 +1,28 @@
/*
* 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.debug;
import org.teavm.model.MethodReference;
public interface DebugLines {
void advance(int ptr);
void location(String file, int line);
void start(MethodReference methodReference);
void end();
}

View File

@ -0,0 +1,109 @@
/*
* 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.debug;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Objects;
import org.teavm.model.MethodReference;
public class DebugLinesBuilder extends DebugSectionBuilder implements DebugLines {
private DebugFiles files;
private DebugMethods methods;
private int ptr;
private int lastWrittenPtr;
private String file;
private int line = 1;
private Deque<State> states = new ArrayDeque<>();
public DebugLinesBuilder(DebugFiles files, DebugMethods methods) {
this.files = files;
this.methods = methods;
}
@Override
public void advance(int ptr) {
if (ptr < this.ptr) {
throw new IllegalArgumentException();
}
this.ptr = ptr;
}
@Override
public void location(String file, int line) {
if (Objects.equals(file, this.file) && this.ptr != lastWrittenPtr && this.line != line) {
if (this.ptr - lastWrittenPtr < 32 && Math.abs(this.line - line) <= 3) {
blob.writeByte(DebugConstants.LOC_USER + 32 * (this.ptr - lastWrittenPtr) + (line - this.line) + 3);
this.line = line;
lastWrittenPtr = ptr;
return;
}
}
if (!Objects.equals(file, this.file)) {
flushPtr();
this.line = 1;
this.file = file;
blob.writeByte(DebugConstants.LOC_FILE).writeLEB(file != null ? files.filePtr(file) : 0);
}
if (this.line != line) {
flushPtr();
blob.writeByte(DebugConstants.LOC_LINE).writeSLEB(line - this.line);
this.line = line;
}
}
private void flushPtr() {
if (ptr != lastWrittenPtr) {
blob.writeLEB(DebugConstants.LOC_PTR);
blob.writeLEB(ptr - lastWrittenPtr);
lastWrittenPtr = ptr;
}
}
@Override
public void start(MethodReference methodReference) {
flushPtr();
blob.writeLEB(DebugConstants.LOC_START);
blob.writeLEB(methods.methodPtr(methodReference));
states.push(new State(file, line));
file = null;
line = 1;
}
@Override
public void end() {
flushPtr();
blob.writeLEB(DebugConstants.LOC_END);
if (!states.isEmpty()) {
var state = states.pop();
file = state.file;
line = state.line;
} else {
file = null;
line = 1;
}
}
private static class State {
String file;
int line;
State(String file, int line) {
this.file = file;
this.line = line;
}
}
}

View File

@ -0,0 +1,22 @@
/*
* 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.debug;
import org.teavm.model.MethodReference;
public interface DebugMethods {
int methodPtr(MethodReference method);
}

View File

@ -0,0 +1,43 @@
/*
* 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.debug;
import com.carrotsearch.hppc.ObjectIntHashMap;
import com.carrotsearch.hppc.ObjectIntMap;
import org.teavm.model.MethodReference;
public class DebugMethodsBuilder extends DebugSectionBuilder implements DebugMethods {
private DebugClasses classes;
private DebugStrings strings;
private ObjectIntMap<MethodReference> methods = new ObjectIntHashMap<>();
public DebugMethodsBuilder(DebugClasses classes, DebugStrings strings) {
this.classes = classes;
this.strings = strings;
}
@Override
public int methodPtr(MethodReference method) {
var result = methods.getOrDefault(method, -1);
if (result < 0) {
result = methods.size();
methods.put(method, result);
blob.writeLEB(classes.classPtr(method.getClassName()));
blob.writeLEB(strings.stringPtr(method.getName()));
}
return result;
}
}

View File

@ -0,0 +1,20 @@
/*
* 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.debug;
public interface DebugPackages {
int packagePtr(int basePackage, String name);
}

View File

@ -0,0 +1,69 @@
/*
* 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.debug;
import com.carrotsearch.hppc.ObjectIntHashMap;
import com.carrotsearch.hppc.ObjectIntMap;
import java.util.Objects;
public class DebugPackagesBuilder extends DebugSectionBuilder implements DebugPackages {
private DebugStrings strings;
private ObjectIntMap<PackageInfo> packages = new ObjectIntHashMap<>();
public DebugPackagesBuilder(DebugStrings strings) {
this.strings = strings;
}
@Override
public int packagePtr(int basePackage, String name) {
var key = new PackageInfo(basePackage, name);
var result = packages.getOrDefault(key, -1);
if (result < 0) {
result = packages.size() + 1;
packages.put(key, result);
blob.writeLEB(basePackage);
blob.writeLEB(strings.stringPtr(name));
}
return result;
}
private static class PackageInfo {
private int parent;
private String name;
PackageInfo(int parent, String name) {
this.parent = parent;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
PackageInfo that = (PackageInfo) o;
return parent == that.parent && name.equals(that.name);
}
@Override
public int hashCode() {
return Objects.hash(parent, name);
}
}
}

View File

@ -0,0 +1,35 @@
/*
* 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.debug;
import org.teavm.backend.wasm.blob.BinaryDataConsumer;
import org.teavm.backend.wasm.blob.Blob;
public class DebugSectionBuilder {
protected Blob blob = new Blob();
public void read(BinaryDataConsumer consumer) {
blob.newReader(consumer).readRemaining();
}
public byte[] build() {
return blob.toArray();
}
public boolean isEmpty() {
return blob.size() == 0;
}
}

View File

@ -0,0 +1,20 @@
/*
* 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.debug;
public interface DebugStrings {
int stringPtr(String str);
}

View File

@ -0,0 +1,36 @@
/*
* 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.debug;
import com.carrotsearch.hppc.ObjectIntHashMap;
import com.carrotsearch.hppc.ObjectIntMap;
import java.nio.charset.StandardCharsets;
public class DebugStringsBuilder extends DebugSectionBuilder implements DebugStrings {
private ObjectIntMap<String> strings = new ObjectIntHashMap<>();
@Override
public int stringPtr(String str) {
var result = strings.getOrDefault(str, -1);
if (result < 0) {
result = strings.size();
strings.put(str, result);
blob.writeLEB(str.length());
blob.write(str.getBytes(StandardCharsets.UTF_8));
}
return result;
}
}

View File

@ -16,7 +16,7 @@
package org.teavm.backend.wasm.dwarf;
import java.util.function.Consumer;
import org.teavm.backend.wasm.dwarf.blob.Blob;
import org.teavm.backend.wasm.blob.Blob;
public class DwarfAbbreviation {
int tag;

View File

@ -22,9 +22,9 @@ import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import org.teavm.backend.wasm.dwarf.blob.BinaryDataConsumer;
import org.teavm.backend.wasm.dwarf.blob.Blob;
import org.teavm.backend.wasm.dwarf.blob.Marker;
import org.teavm.backend.wasm.blob.BinaryDataConsumer;
import org.teavm.backend.wasm.blob.Blob;
import org.teavm.backend.wasm.blob.Marker;
public class DwarfInfoWriter {
private Blob output = new Blob();

View File

@ -17,7 +17,7 @@ package org.teavm.backend.wasm.dwarf;
import java.util.ArrayList;
import java.util.List;
import org.teavm.backend.wasm.dwarf.blob.Marker;
import org.teavm.backend.wasm.blob.Marker;
public class DwarfPlaceholder {
int ptr = -1;

View File

@ -15,7 +15,7 @@
*/
package org.teavm.backend.wasm.dwarf;
import org.teavm.backend.wasm.dwarf.blob.Blob;
import org.teavm.backend.wasm.blob.Blob;
public interface DwarfPlaceholderWriter {
void write(Blob blob, int actualValue);

View File

@ -46,10 +46,10 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.teavm.backend.wasm.blob.Blob;
import org.teavm.backend.wasm.dwarf.DwarfAbbreviation;
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.model.MethodDescriptor;
import org.teavm.model.PrimitiveType;
import org.teavm.model.ValueType;

View File

@ -30,9 +30,9 @@ 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.blob.Blob;
import org.teavm.backend.wasm.blob.Marker;
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;
import org.teavm.model.util.VariableType;

View File

@ -31,10 +31,10 @@ 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.ArrayList;
import java.util.Collection;
import org.teavm.backend.wasm.blob.Blob;
import org.teavm.backend.wasm.blob.Marker;
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 {

View File

@ -26,8 +26,8 @@ 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;
import org.teavm.backend.wasm.blob.Blob;
import org.teavm.backend.wasm.blob.Marker;
class DwarfLinesGenerator {
private static final int MIN_INSN_LEN = 1;

View File

@ -18,7 +18,7 @@ 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;
import org.teavm.backend.wasm.blob.Blob;
public class DwarfStrings {
final Blob blob = new Blob();

View File

@ -59,6 +59,7 @@ public class WasmGenerator {
ClassHolder cls = classSource.get(methodReference.getClassName());
MethodHolder method = cls.getMethod(methodReference.getDescriptor());
WasmFunction function = new WasmFunction(names.forMethod(method.getReference()));
function.setJavaMethod(methodReference);
if (!method.hasModifier(ElementModifier.STATIC)) {
function.getParameters().add(WasmType.INT32);

View File

@ -20,6 +20,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.model.MethodReference;
public class WasmFunction {
WasmModule module;
@ -32,6 +33,7 @@ public class WasmFunction {
private List<WasmLocal> localVariables = new ArrayList<>();
private List<WasmLocal> readonlyLocalVariables = Collections.unmodifiableList(localVariables);
private List<WasmExpression> body = new ArrayList<>();
private MethodReference javaMethod;
public WasmFunction(String name) {
Objects.requireNonNull(name);
@ -98,4 +100,12 @@ public class WasmFunction {
local.index = localVariables.size();
localVariables.add(local);
}
public MethodReference getJavaMethod() {
return javaMethod;
}
public void setJavaMethod(MethodReference javaMethod) {
this.javaMethod = javaMethod;
}
}

View File

@ -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.debug.DebugLines;
import org.teavm.backend.wasm.generate.DwarfClassGenerator;
import org.teavm.backend.wasm.generate.DwarfFunctionGenerator;
import org.teavm.backend.wasm.generate.DwarfGenerator;
@ -57,14 +58,16 @@ public class WasmBinaryRenderer {
private boolean obfuscated;
private DwarfGenerator dwarfGenerator;
private DwarfFunctionGenerator dwarfFunctionGen;
private DebugLines debugLines;
public WasmBinaryRenderer(WasmBinaryWriter output, WasmBinaryVersion version, boolean obfuscated,
DwarfGenerator dwarfGenerator, DwarfClassGenerator dwarfClassGen) {
DwarfGenerator dwarfGenerator, DwarfClassGenerator dwarfClassGen, DebugLines debugLines) {
this.output = output;
this.version = version;
this.obfuscated = obfuscated;
this.dwarfGenerator = dwarfGenerator;
dwarfFunctionGen = dwarfClassGen != null ? new DwarfFunctionGenerator(dwarfClassGen, dwarfGenerator) : null;
this.debugLines = debugLines;
}
public void render(WasmModule module) {
@ -288,7 +291,9 @@ public class WasmBinaryRenderer {
if (dwarfFunctionGen != null) {
dwarfFunctionGen.begin(function, offset);
}
if (debugLines != null && function.getJavaMethod() != null) {
debugLines.start(function.getJavaMethod());
}
var localVariables = function.getLocalVariables();
@ -319,7 +324,7 @@ public class WasmBinaryRenderer {
var importIndexes = this.functionIndexes;
var visitor = new WasmBinaryRenderingVisitor(code, version, functionIndexes, importIndexes,
signatureIndexes, dwarfGenerator, offset);
signatureIndexes, dwarfGenerator, function.getJavaMethod() != null ? debugLines : null, offset);
for (var part : function.getBody()) {
part.acceptVisitor(visitor);
}
@ -327,6 +332,9 @@ public class WasmBinaryRenderer {
if (dwarfGenerator != null) {
dwarfGenerator.endLineNumberSequence(offset + code.getPosition());
}
if (debugLines != null) {
debugLines.end();
}
code.writeByte(0x0B);

View File

@ -15,8 +15,12 @@
*/
package org.teavm.backend.wasm.render;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.teavm.backend.wasm.debug.DebugLines;
import org.teavm.backend.wasm.generate.DwarfGenerator;
import org.teavm.backend.wasm.model.WasmType;
import org.teavm.backend.wasm.model.expression.WasmBlock;
@ -51,6 +55,7 @@ import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
import org.teavm.backend.wasm.model.expression.WasmSwitch;
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
import org.teavm.model.MethodReference;
class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
private WasmBinaryWriter writer;
@ -59,13 +64,16 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
private Map<String, Integer> importedIndexes;
private Map<WasmSignature, Integer> signatureIndexes;
private DwarfGenerator dwarfGenerator;
private DebugLines debugLines;
private int addressOffset;
private int depth;
private Map<WasmBlock, Integer> blockDepths = new HashMap<>();
private List<MethodReference> methodStack = new ArrayList<>();
private List<MethodReference> currentMethodStack = new ArrayList<>();
WasmBinaryRenderingVisitor(WasmBinaryWriter writer, WasmBinaryVersion version, Map<String, Integer> functionIndexes,
Map<String, Integer> importedIndexes, Map<WasmSignature, Integer> signatureIndexes,
DwarfGenerator dwarfGenerator, int addressOffset) {
DwarfGenerator dwarfGenerator, DebugLines debugLines, int addressOffset) {
this.writer = writer;
this.version = version;
this.functionIndexes = functionIndexes;
@ -73,6 +81,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
this.signatureIndexes = signatureIndexes;
this.dwarfGenerator = dwarfGenerator;
this.addressOffset = addressOffset;
this.debugLines = debugLines;
}
@Override
@ -875,11 +884,38 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
}
private void emitLocation(WasmExpression expression) {
if (dwarfGenerator == null || expression.getLocation() == null
|| expression.getLocation().getFileName() == null) {
if (expression.getLocation() == null || expression.getLocation().getFileName() == null) {
return;
}
dwarfGenerator.lineNumber(writer.getPosition() + addressOffset, expression.getLocation().getFileName(),
expression.getLocation().getLine());
if (dwarfGenerator != null) {
dwarfGenerator.lineNumber(writer.getPosition() + addressOffset, expression.getLocation().getFileName(),
expression.getLocation().getLine());
}
if (debugLines != null) {
debugLines.advance(writer.getPosition() + addressOffset);
var loc = expression.getLocation();
var inlining = loc.getInlining();
while (inlining != null) {
currentMethodStack.add(loc.getInlining().getMethod());
inlining = inlining.getParent();
}
Collections.reverse(currentMethodStack);
var commonPart = 0;
while (commonPart < currentMethodStack.size() && commonPart < methodStack.size()
&& currentMethodStack.get(commonPart).equals(methodStack.get(commonPart))) {
++commonPart;
}
while (methodStack.size() > commonPart) {
debugLines.end();
methodStack.remove(methodStack.size() - 1);
}
while (commonPart < currentMethodStack.size()) {
var method = currentMethodStack.get(commonPart);
methodStack.add(method);
debugLines.start(method);
}
currentMethodStack.clear();
debugLines.location(loc.getFileName(), loc.getLine());
}
}
}