mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Wasm: generate debugging information for own debugger
This commit is contained in:
parent
7e95e935d1
commit
56929b2085
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()));
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user