mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Wasm: support local variables in debugger
This commit is contained in:
parent
7e3197429d
commit
6808d9e517
|
@ -552,8 +552,11 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
|
||||
var writer = new WasmBinaryWriter();
|
||||
var debugBuilder = debugging ? new DebugInfoBuilder() : null;
|
||||
var renderer = new WasmBinaryRenderer(writer, version, obfuscated, dwarfGenerator, dwarfClassGen,
|
||||
debugBuilder != null ? debugBuilder.lines() : null);
|
||||
var renderer = new WasmBinaryRenderer(
|
||||
writer, version, obfuscated, dwarfGenerator, dwarfClassGen,
|
||||
debugBuilder != null ? debugBuilder.lines() : null,
|
||||
debugBuilder != null ? debugBuilder.variables() : null
|
||||
);
|
||||
renderer.render(module, buildDebug(dwarfGenerator, dwarfClassGen, debugBuilder));
|
||||
|
||||
try (OutputStream output = buildTarget.createResource(outputName)) {
|
||||
|
|
|
@ -32,4 +32,5 @@ public final class DebugConstants {
|
|||
public static final String SECTION_CLASSES = "teavm_cls";
|
||||
public static final String SECTION_METHODS = "teavm_mtd";
|
||||
public static final String SECTION_LINES = "teavm_line";
|
||||
public static final String SECTION_VARIABLES = "teavm_var";
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ public class DebugInfoBuilder {
|
|||
private DebugPackagesBuilder packages;
|
||||
private DebugClassesBuilder classes;
|
||||
private DebugMethodsBuilder methods;
|
||||
private DebugVariablesBuilder variables;
|
||||
private DebugLinesBuilder lines;
|
||||
|
||||
public DebugInfoBuilder() {
|
||||
|
@ -33,6 +34,7 @@ public class DebugInfoBuilder {
|
|||
packages = new DebugPackagesBuilder(strings);
|
||||
classes = new DebugClassesBuilder(packages, strings);
|
||||
methods = new DebugMethodsBuilder(classes, strings);
|
||||
variables = new DebugVariablesBuilder(strings);
|
||||
lines = new DebugLinesBuilder(files, methods);
|
||||
}
|
||||
|
||||
|
@ -52,11 +54,15 @@ public class DebugInfoBuilder {
|
|||
return classes;
|
||||
}
|
||||
|
||||
public DebugMethodsBuilder methods() {
|
||||
public DebugMethods methods() {
|
||||
return methods;
|
||||
}
|
||||
|
||||
public DebugLinesBuilder lines() {
|
||||
public DebugVariables variables() {
|
||||
return variables;
|
||||
}
|
||||
|
||||
public DebugLines lines() {
|
||||
return lines;
|
||||
}
|
||||
|
||||
|
@ -67,6 +73,7 @@ public class DebugInfoBuilder {
|
|||
addSection(result, packages);
|
||||
addSection(result, classes);
|
||||
addSection(result, methods);
|
||||
addSection(result, variables);
|
||||
addSection(result, lines);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ import com.carrotsearch.hppc.ObjectIntHashMap;
|
|||
import com.carrotsearch.hppc.ObjectIntMap;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class DebugMethodsBuilder extends DebugSectionBuilder implements DebugMethods {
|
||||
public class DebugMethodsBuilder extends DebugSectionBuilder implements DebugMethods {
|
||||
private DebugClasses classes;
|
||||
private DebugStrings strings;
|
||||
private ObjectIntMap<MethodReference> methods = new ObjectIntHashMap<>();
|
||||
|
|
|
@ -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.backend.wasm.debug.info.VariableType;
|
||||
|
||||
public interface DebugVariables {
|
||||
void startSequence(int pointer);
|
||||
|
||||
void type(String name, VariableType type);
|
||||
|
||||
void range(String name, int start, int end, int pointer);
|
||||
|
||||
void endSequence();
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.teavm.backend.wasm.debug.info.VariableType;
|
||||
|
||||
public class DebugVariablesBuilder extends DebugSectionBuilder implements DebugVariables {
|
||||
private DebugStrings strings;
|
||||
private int sequenceStart;
|
||||
private int lastSequenceStart;
|
||||
private Map<String, VarInfo> variables = new LinkedHashMap<>();
|
||||
|
||||
public DebugVariablesBuilder(DebugStrings strings) {
|
||||
super(DebugConstants.SECTION_VARIABLES);
|
||||
this.strings = strings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startSequence(int pointer) {
|
||||
sequenceStart = pointer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void type(String name, VariableType type) {
|
||||
getInfo(name).type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void range(String name, int start, int end, int pointer) {
|
||||
getInfo(name).ranges.add(new Range(start, end, pointer));
|
||||
}
|
||||
|
||||
private VarInfo getInfo(String name) {
|
||||
var info = variables.get(name);
|
||||
if (info == null) {
|
||||
info = new VarInfo();
|
||||
variables.put(name, info);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endSequence() {
|
||||
if (variables.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
blob.writeLEB(sequenceStart - lastSequenceStart);
|
||||
lastSequenceStart = sequenceStart;
|
||||
blob.writeLEB(variables.size());
|
||||
for (var variable : variables.entrySet()) {
|
||||
blob.writeLEB(strings.stringPtr(variable.getKey()));
|
||||
var info = variable.getValue();
|
||||
blob.writeLEB(info.type.ordinal());
|
||||
blob.writeLEB(info.ranges.size());
|
||||
var lastPtr = sequenceStart;
|
||||
var lastPointer = 0;
|
||||
for (var range : info.ranges) {
|
||||
blob.writeSLEB(range.start - lastPtr);
|
||||
blob.writeLEB(range.end - range.start);
|
||||
blob.writeSLEB(range.pointer - lastPointer);
|
||||
lastPointer = range.pointer;
|
||||
lastPointer = range.end;
|
||||
}
|
||||
}
|
||||
variables.clear();
|
||||
}
|
||||
|
||||
private static class VarInfo {
|
||||
VariableType type = VariableType.UNDEFINED;
|
||||
List<Range> ranges = new ArrayList<>();
|
||||
}
|
||||
|
||||
private static class Range {
|
||||
int start;
|
||||
int end;
|
||||
int pointer;
|
||||
|
||||
Range(int start, int end, int pointer) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.pointer = pointer;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,16 +18,22 @@ package org.teavm.backend.wasm.debug.info;
|
|||
import java.io.PrintStream;
|
||||
|
||||
public class DebugInfo {
|
||||
private VariablesInfo variables;
|
||||
private LineInfo lines;
|
||||
private ControlFlowInfo controlFlow;
|
||||
private int offset;
|
||||
|
||||
public DebugInfo(LineInfo lines, ControlFlowInfo controlFlow, int offset) {
|
||||
public DebugInfo(VariablesInfo variables, LineInfo lines, ControlFlowInfo controlFlow, int offset) {
|
||||
this.variables = variables;
|
||||
this.lines = lines;
|
||||
this.controlFlow = controlFlow;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
public VariablesInfo variables() {
|
||||
return variables;
|
||||
}
|
||||
|
||||
public LineInfo lines() {
|
||||
return lines;
|
||||
}
|
||||
|
@ -52,5 +58,9 @@ public class DebugInfo {
|
|||
out.println("CONTROL FLOW");
|
||||
controlFlow.dump(out);
|
||||
}
|
||||
if (variables != null) {
|
||||
out.println("VARIABLES");
|
||||
variables.dump(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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.info;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public abstract class VariableInfo {
|
||||
public abstract String name();
|
||||
|
||||
public abstract VariableType type();
|
||||
|
||||
public abstract Collection<? extends VariableRangeInfo> ranges();
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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.info;
|
||||
|
||||
public abstract class VariableRangeInfo {
|
||||
public abstract VariableInfo variable();
|
||||
|
||||
public abstract int start();
|
||||
|
||||
public abstract int end();
|
||||
|
||||
public abstract int index();
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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.info;
|
||||
|
||||
public enum VariableType {
|
||||
INT,
|
||||
LONG,
|
||||
FLOAT,
|
||||
DOUBLE,
|
||||
OBJECT,
|
||||
ADDRESS,
|
||||
UNDEFINED
|
||||
}
|
|
@ -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.info;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class VariablesInfo {
|
||||
public abstract List<? extends VariableRangeInfo> ranges();
|
||||
|
||||
public Collection<? extends VariableRangeInfo> find(int address) {
|
||||
var result = new ArrayList<VariableRangeInfo>();
|
||||
for (var range : ranges()) {
|
||||
if (address >= range.start() && address < range.end()) {
|
||||
result.add(range);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void dump(PrintStream out) {
|
||||
for (var range : ranges()) {
|
||||
out.println(range.variable().name() + ": " + range.variable().type() + " - "
|
||||
+ Integer.toHexString(range.start()) + ".." + Integer.toHexString(range.end()) + " at "
|
||||
+ range.index());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,6 +31,7 @@ import org.teavm.common.ByteArrayAsyncInputStream;
|
|||
public class DebugInfoParser extends ModuleParser {
|
||||
private Map<String, DebugSectionParser> sectionParsers = new HashMap<>();
|
||||
private DebugLinesParser lines;
|
||||
private DebugVariablesParser variables;
|
||||
private ControlFlowInfo controlFlow;
|
||||
private int offset;
|
||||
|
||||
|
@ -41,6 +42,7 @@ public class DebugInfoParser extends ModuleParser {
|
|||
var packages = addSection(new DebugPackageParser(strings));
|
||||
var classes = addSection(new DebugClassParser(strings, packages));
|
||||
var methods = addSection(new DebugMethodParser(strings, classes));
|
||||
variables = addSection(new DebugVariablesParser(strings));
|
||||
lines = addSection(new DebugLinesParser(files, methods));
|
||||
}
|
||||
|
||||
|
@ -50,7 +52,7 @@ public class DebugInfoParser extends ModuleParser {
|
|||
}
|
||||
|
||||
public DebugInfo getDebugInfo() {
|
||||
return new DebugInfo(lines.getLineInfo(), controlFlow, offset);
|
||||
return new DebugInfo(variables.getVariablesInfo(), lines.getLineInfo(), controlFlow, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* 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.parser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import org.teavm.backend.wasm.debug.DebugConstants;
|
||||
import org.teavm.backend.wasm.debug.info.VariableInfo;
|
||||
import org.teavm.backend.wasm.debug.info.VariableRangeInfo;
|
||||
import org.teavm.backend.wasm.debug.info.VariableType;
|
||||
import org.teavm.backend.wasm.debug.info.VariablesInfo;
|
||||
|
||||
public class DebugVariablesParser extends DebugSectionParser {
|
||||
private static final VariableType[] typeByOrdinal = VariableType.values();
|
||||
private DebugStringParser strings;
|
||||
private VariablesInfoImpl variablesInfo;
|
||||
|
||||
public DebugVariablesParser(DebugStringParser strings) {
|
||||
super(DebugConstants.SECTION_VARIABLES, strings);
|
||||
this.strings = strings;
|
||||
}
|
||||
|
||||
public VariablesInfoImpl getVariablesInfo() {
|
||||
return variablesInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doParse() {
|
||||
var lastAddress = 0;
|
||||
var ranges = new ArrayList<VariableRangeInfo>();
|
||||
var localRanges = new ArrayList<VariableRangeInfoImpl>();
|
||||
while (ptr < data.length) {
|
||||
var baseAddress = lastAddress + readLEB();
|
||||
lastAddress = baseAddress;
|
||||
var variableCount = readLEB();
|
||||
for (var i = 0; i < variableCount; ++i) {
|
||||
var name = strings.getString(readLEB());
|
||||
var type = typeByOrdinal[readLEB()];
|
||||
var rangeCount = readLEB();
|
||||
var varInfo = new VariableInfoImpl(name, type);
|
||||
var address = baseAddress;
|
||||
var lastLocation = 0;
|
||||
for (var j = 0; j < rangeCount; ++j) {
|
||||
var start = address + readSignedLEB();
|
||||
var size = readLEB();
|
||||
var end = start + size;
|
||||
address = end;
|
||||
var location = lastLocation + readSignedLEB();
|
||||
lastLocation = location;
|
||||
var rangeInfo = new VariableRangeInfoImpl(varInfo, start, end, location);
|
||||
ranges.add(rangeInfo);
|
||||
localRanges.add(rangeInfo);
|
||||
}
|
||||
localRanges.clear();
|
||||
varInfo.ranges = Collections.unmodifiableList(Arrays.asList(
|
||||
localRanges.toArray(new VariableRangeInfoImpl[0])));
|
||||
}
|
||||
}
|
||||
ranges.sort(Comparator.comparing(VariableRangeInfo::start));
|
||||
|
||||
this.variablesInfo = new VariablesInfoImpl(Collections.unmodifiableList(Arrays.asList(
|
||||
ranges.toArray(new VariableRangeInfoImpl[0]))));
|
||||
}
|
||||
|
||||
private static class VariablesInfoImpl extends VariablesInfo {
|
||||
private List<VariableRangeInfoImpl> ranges;
|
||||
|
||||
VariablesInfoImpl(List<VariableRangeInfoImpl> ranges) {
|
||||
this.ranges = ranges;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends VariableRangeInfo> ranges() {
|
||||
return ranges;
|
||||
}
|
||||
}
|
||||
|
||||
private static class VariableInfoImpl extends VariableInfo {
|
||||
private String name;
|
||||
private VariableType type;
|
||||
private List<VariableRangeInfoImpl> ranges;
|
||||
|
||||
VariableInfoImpl(String name, VariableType type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableType type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends VariableRangeInfo> ranges() {
|
||||
return ranges;
|
||||
}
|
||||
}
|
||||
|
||||
private static class VariableRangeInfoImpl extends VariableRangeInfo {
|
||||
private VariableInfoImpl variableInfo;
|
||||
private int start;
|
||||
private int end;
|
||||
private int index;
|
||||
|
||||
VariableRangeInfoImpl(VariableInfoImpl variableInfo, int start, int end, int index) {
|
||||
this.variableInfo = variableInfo;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableInfo variable() {
|
||||
return variableInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int start() {
|
||||
return start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int end() {
|
||||
return end;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int index() {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -47,13 +47,13 @@ import java.util.LinkedHashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.teavm.backend.wasm.blob.Blob;
|
||||
import org.teavm.backend.wasm.debug.info.VariableType;
|
||||
import org.teavm.backend.wasm.dwarf.DwarfAbbreviation;
|
||||
import org.teavm.backend.wasm.dwarf.DwarfInfoWriter;
|
||||
import org.teavm.backend.wasm.dwarf.DwarfPlaceholder;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.PrimitiveType;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.util.VariableType;
|
||||
|
||||
public class DwarfClassGenerator {
|
||||
private static final ValueType objectType = ValueType.object("java.lang.Object");
|
||||
|
|
|
@ -32,9 +32,9 @@ 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.debug.info.VariableType;
|
||||
import org.teavm.backend.wasm.dwarf.DwarfAbbreviation;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.model.util.VariableType;
|
||||
|
||||
public class DwarfFunctionGenerator {
|
||||
private DwarfClassGenerator classGen;
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.teavm.ast.VariableNode;
|
|||
import org.teavm.ast.decompilation.Decompiler;
|
||||
import org.teavm.backend.lowlevel.generate.NameProvider;
|
||||
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||
import org.teavm.backend.wasm.debug.info.VariableType;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
|
@ -87,7 +88,7 @@ public class WasmGenerator {
|
|||
? WasmGeneratorUtil.mapType(variable.getType())
|
||||
: WasmType.INT32;
|
||||
var local = new WasmLocal(type, variable.getName());
|
||||
local.setJavaType(variable.getType());
|
||||
local.setJavaType(mapType(variable.getType()));
|
||||
function.add(local);
|
||||
}
|
||||
|
||||
|
@ -107,6 +108,21 @@ public class WasmGenerator {
|
|||
return function;
|
||||
}
|
||||
|
||||
private VariableType mapType(org.teavm.model.util.VariableType type) {
|
||||
switch (type) {
|
||||
case INT:
|
||||
return VariableType.INT;
|
||||
case LONG:
|
||||
return VariableType.LONG;
|
||||
case FLOAT:
|
||||
return VariableType.FLOAT;
|
||||
case DOUBLE:
|
||||
return VariableType.DOUBLE;
|
||||
default:
|
||||
return VariableType.OBJECT;
|
||||
}
|
||||
}
|
||||
|
||||
public WasmFunction generateNative(MethodReference methodReference) {
|
||||
WasmFunction function = context.getFunction(names.forMethod(methodReference));
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
package org.teavm.backend.wasm.model;
|
||||
|
||||
import java.util.Objects;
|
||||
import org.teavm.model.util.VariableType;
|
||||
import org.teavm.backend.wasm.debug.info.VariableType;
|
||||
|
||||
public class WasmLocal {
|
||||
WasmFunction function;
|
||||
|
|
|
@ -24,6 +24,7 @@ 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.debug.DebugVariables;
|
||||
import org.teavm.backend.wasm.generate.DwarfClassGenerator;
|
||||
import org.teavm.backend.wasm.generate.DwarfFunctionGenerator;
|
||||
import org.teavm.backend.wasm.generate.DwarfGenerator;
|
||||
|
@ -59,15 +60,18 @@ public class WasmBinaryRenderer {
|
|||
private DwarfGenerator dwarfGenerator;
|
||||
private DwarfFunctionGenerator dwarfFunctionGen;
|
||||
private DebugLines debugLines;
|
||||
private DebugVariables debugVariables;
|
||||
|
||||
public WasmBinaryRenderer(WasmBinaryWriter output, WasmBinaryVersion version, boolean obfuscated,
|
||||
DwarfGenerator dwarfGenerator, DwarfClassGenerator dwarfClassGen, DebugLines debugLines) {
|
||||
DwarfGenerator dwarfGenerator, DwarfClassGenerator dwarfClassGen, DebugLines debugLines,
|
||||
DebugVariables debugVariables) {
|
||||
this.output = output;
|
||||
this.version = version;
|
||||
this.obfuscated = obfuscated;
|
||||
this.dwarfGenerator = dwarfGenerator;
|
||||
dwarfFunctionGen = dwarfClassGen != null ? new DwarfFunctionGenerator(dwarfClassGen, dwarfGenerator) : null;
|
||||
this.debugLines = debugLines;
|
||||
this.debugVariables = debugVariables;
|
||||
}
|
||||
|
||||
public void render(WasmModule module) {
|
||||
|
@ -335,10 +339,24 @@ public class WasmBinaryRenderer {
|
|||
if (dwarfFunctionGen != null) {
|
||||
dwarfFunctionGen.end(code.getPosition());
|
||||
}
|
||||
if (debugVariables != null) {
|
||||
writeDebugVariables(function, offset, code.getPosition());
|
||||
}
|
||||
|
||||
return code.getData();
|
||||
}
|
||||
|
||||
private void writeDebugVariables(WasmFunction function, int offset, int size) {
|
||||
debugVariables.startSequence(offset);
|
||||
for (var local : function.getLocalVariables()) {
|
||||
if (local.getName() != null && local.getJavaType() != null) {
|
||||
debugVariables.type(local.getName(), local.getJavaType());
|
||||
debugVariables.range(local.getName(), offset, offset + size, local.getIndex());
|
||||
}
|
||||
}
|
||||
debugVariables.endSequence();
|
||||
}
|
||||
|
||||
private void renderInitializer(WasmBinaryWriter output, int value) {
|
||||
output.writeByte(0x41);
|
||||
output.writeLEB(value);
|
||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.debugging;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import org.teavm.backend.wasm.debug.info.DebugInfo;
|
||||
import org.teavm.common.Promise;
|
||||
import org.teavm.debugging.information.DebugInformation;
|
||||
import org.teavm.debugging.information.SourceLocation;
|
||||
|
@ -31,14 +32,16 @@ public class CallFrame {
|
|||
private MethodReference method;
|
||||
private Promise<Map<String, Variable>> variables;
|
||||
private DebugInformation debugInformation;
|
||||
private DebugInfo wasmDebugInfo;
|
||||
|
||||
CallFrame(Debugger debugger, JavaScriptCallFrame originalFrame, SourceLocation location, MethodReference method,
|
||||
DebugInformation debugInformation) {
|
||||
DebugInformation debugInformation, DebugInfo wasmDebugInfo) {
|
||||
this.debugger = debugger;
|
||||
this.originalCallFrame = originalFrame;
|
||||
this.location = location;
|
||||
this.method = method;
|
||||
this.debugInformation = debugInformation;
|
||||
this.wasmDebugInfo = wasmDebugInfo;
|
||||
}
|
||||
|
||||
public Debugger getDebugger() {
|
||||
|
@ -65,6 +68,8 @@ public class CallFrame {
|
|||
if (variables == null) {
|
||||
if (debugInformation != null) {
|
||||
variables = debugger.createVariables(originalCallFrame, debugInformation);
|
||||
} else if (wasmDebugInfo != null) {
|
||||
variables = debugger.createVariables(originalCallFrame, wasmDebugInfo);
|
||||
} else {
|
||||
variables = Promise.of(Collections.emptyMap());
|
||||
}
|
||||
|
|
|
@ -403,6 +403,7 @@ public class Debugger {
|
|||
for (var jsFrame : javaScriptDebugger.getCallStack()) {
|
||||
List<SourceLocationWithMethod> locations;
|
||||
DebugInformation debugInformation = null;
|
||||
DebugInfo wasmDebugInfo = null;
|
||||
switch (jsFrame.getLocation().getScript().getLanguage()) {
|
||||
case JS:
|
||||
debugInformation = debugInformationMap.get(jsFrame.getLocation().getScript());
|
||||
|
@ -410,6 +411,9 @@ public class Debugger {
|
|||
break;
|
||||
case WASM:
|
||||
locations = mapWasmFrames(jsFrame);
|
||||
if (!locations.isEmpty()) {
|
||||
wasmDebugInfo = wasmDebugInfoMap.get(jsFrame.getLocation().getScript());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
locations = Collections.emptyList();
|
||||
|
@ -419,7 +423,7 @@ public class Debugger {
|
|||
var loc = locWithMethod.loc;
|
||||
var method = locWithMethod.method;
|
||||
if (!locWithMethod.empty || !wasEmpty) {
|
||||
frames.add(new CallFrame(this, jsFrame, loc, method, debugInformation));
|
||||
frames.add(new CallFrame(this, jsFrame, loc, method, debugInformation, wasmDebugInfo));
|
||||
}
|
||||
wasEmpty = locWithMethod.empty;
|
||||
}
|
||||
|
@ -513,6 +517,36 @@ public class Debugger {
|
|||
});
|
||||
}
|
||||
|
||||
Promise<Map<String, Variable>> createVariables(JavaScriptCallFrame jsFrame, DebugInfo debugInfo) {
|
||||
return jsFrame.getVariables().thenAsync(jsVariables -> {
|
||||
var vars = new HashMap<String, Variable>();
|
||||
var variables = debugInfo.variables();
|
||||
var promises = new ArrayList<Promise<Void>>();
|
||||
if (variables != null) {
|
||||
var address = jsFrame.getLocation().getColumn();
|
||||
address -= debugInfo.offset();
|
||||
for (var range : variables.find(address)) {
|
||||
var propertiesPromise = jsVariables.get("$var" + range.index()).getValue().getProperties();
|
||||
promises.add(propertiesPromise
|
||||
.then(prop -> {
|
||||
var variable = prop.get("value");
|
||||
return variable != null ? variable.getValue() : null;
|
||||
})
|
||||
.thenAsync(value -> {
|
||||
if (value != null) {
|
||||
var varValue = new Value(this, debugInfo, value);
|
||||
var variable = new Variable(range.variable().name(), varValue);
|
||||
vars.put(variable.getName(), variable);
|
||||
}
|
||||
return Promise.VOID;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
return Promise.allVoid(promises).then(x -> vars);
|
||||
});
|
||||
}
|
||||
|
||||
private void addScript(JavaScriptScript script) {
|
||||
Promise<Void> promise;
|
||||
switch (script.getLanguage()) {
|
||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.debugging;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.teavm.backend.wasm.debug.info.DebugInfo;
|
||||
import org.teavm.common.Promise;
|
||||
import org.teavm.debugging.information.DebugInformation;
|
||||
import org.teavm.debugging.javascript.JavaScriptValue;
|
||||
|
@ -25,6 +26,7 @@ import org.teavm.debugging.javascript.JavaScriptVariable;
|
|||
public class Value {
|
||||
private Debugger debugger;
|
||||
private DebugInformation debugInformation;
|
||||
private DebugInfo wasmDebugInfo;
|
||||
private JavaScriptValue jsValue;
|
||||
private Promise<Map<String, Variable>> properties;
|
||||
private Promise<String> type;
|
||||
|
@ -35,6 +37,12 @@ public class Value {
|
|||
this.jsValue = jsValue;
|
||||
}
|
||||
|
||||
Value(Debugger debugger, DebugInfo wasmDebugInfo, JavaScriptValue jsValue) {
|
||||
this.debugger = debugger;
|
||||
this.wasmDebugInfo = wasmDebugInfo;
|
||||
this.jsValue = jsValue;
|
||||
}
|
||||
|
||||
private static boolean isNumeric(String str) {
|
||||
for (int i = 0; i < str.length(); ++i) {
|
||||
char c = str.charAt(i);
|
||||
|
|
|
@ -86,7 +86,6 @@ public class ChromeRDPDebugger extends BaseChromeRDPDebugger implements JavaScri
|
|||
protected void onDetach() {
|
||||
suspended = false;
|
||||
callStack = null;
|
||||
|
||||
}
|
||||
|
||||
private Promise<Void> injectFunctions(int contextId) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user