mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Wasm: support class layout in debug information
This commit is contained in:
parent
506a9bd8c5
commit
7b3905246b
|
@ -552,6 +552,9 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
|
||||
var writer = new WasmBinaryWriter();
|
||||
var debugBuilder = debugging ? new DebugInfoBuilder() : null;
|
||||
if (debugBuilder != null) {
|
||||
classGenerator.writeDebug(debugBuilder.classLayout());
|
||||
}
|
||||
var renderer = new WasmBinaryRenderer(
|
||||
writer, version, obfuscated, dwarfGenerator, dwarfClassGen,
|
||||
debugBuilder != null ? debugBuilder.lines() : null,
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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.FieldType;
|
||||
import org.teavm.model.PrimitiveType;
|
||||
|
||||
public interface DebugClassLayout {
|
||||
void startClass(String name, int parent, int address, int size);
|
||||
|
||||
void instanceField(String name, int offset, FieldType type);
|
||||
|
||||
void staticField(String name, int offset, FieldType type);
|
||||
|
||||
void endClass();
|
||||
|
||||
void writeInterface(String name, int address);
|
||||
|
||||
void writePrimitive(PrimitiveType type, int address);
|
||||
|
||||
void writeArray(int itemType, int address);
|
||||
|
||||
void writeUnknown(int address);
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* 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.FieldType;
|
||||
import org.teavm.model.PrimitiveType;
|
||||
|
||||
public class DebugClassLayoutBuilder extends DebugSectionBuilder implements DebugClassLayout {
|
||||
private DebugClasses classes;
|
||||
private DebugStrings strings;
|
||||
private int currentIndex;
|
||||
private int currentAddress;
|
||||
private ClassPhase phase = ClassPhase.NO_CLASS;
|
||||
private int lastFieldOffset;
|
||||
|
||||
public DebugClassLayoutBuilder(DebugClasses classes, DebugStrings strings) {
|
||||
super(DebugConstants.SECTION_CLASS_LAYOUT);
|
||||
this.classes = classes;
|
||||
this.strings = strings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startClass(String name, int parent, int address, int size) {
|
||||
blob.writeByte(parent >= 0 ? DebugConstants.CLASS_CLASS : DebugConstants.CLASS_ROOT);
|
||||
blob.writeLEB(classes.classPtr(name));
|
||||
if (parent >= 0) {
|
||||
blob.writeSLEB(currentIndex - parent);
|
||||
}
|
||||
writeAddress(address);
|
||||
blob.writeLEB(size);
|
||||
lastFieldOffset = 0;
|
||||
phase = ClassPhase.STATIC_FIELDS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void instanceField(String name, int offset, FieldType type) {
|
||||
if (phase == ClassPhase.STATIC_FIELDS) {
|
||||
blob.writeByte(DebugConstants.FIELD_END_SEQUENCE);
|
||||
lastFieldOffset = 0;
|
||||
phase = ClassPhase.INSTANCE_FIELDS;
|
||||
}
|
||||
writeFieldType(type);
|
||||
blob.writeLEB(strings.stringPtr(name));
|
||||
blob.writeSLEB(offset - lastFieldOffset);
|
||||
lastFieldOffset = offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void staticField(String name, int offset, FieldType type) {
|
||||
writeFieldType(type);
|
||||
blob.writeLEB(strings.stringPtr(name));
|
||||
blob.writeSLEB(offset - lastFieldOffset);
|
||||
lastFieldOffset = offset;
|
||||
}
|
||||
|
||||
private void writeFieldType(FieldType type) {
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
blob.writeByte(DebugConstants.FIELD_BOOLEAN);
|
||||
break;
|
||||
case BYTE:
|
||||
blob.writeByte(DebugConstants.FIELD_BYTE);
|
||||
break;
|
||||
case SHORT:
|
||||
blob.writeByte(DebugConstants.FIELD_SHORT);
|
||||
break;
|
||||
case CHAR:
|
||||
blob.writeByte(DebugConstants.FIELD_CHAR);
|
||||
break;
|
||||
case INT:
|
||||
blob.writeByte(DebugConstants.FIELD_INT);
|
||||
break;
|
||||
case LONG:
|
||||
blob.writeByte(DebugConstants.FIELD_LONG);
|
||||
break;
|
||||
case FLOAT:
|
||||
blob.writeByte(DebugConstants.FIELD_FLOAT);
|
||||
break;
|
||||
case DOUBLE:
|
||||
blob.writeByte(DebugConstants.FIELD_DOUBLE);
|
||||
break;
|
||||
case OBJECT:
|
||||
blob.writeByte(DebugConstants.FIELD_OBJECT);
|
||||
break;
|
||||
case ADDRESS:
|
||||
blob.writeByte(DebugConstants.FIELD_ADDRESS);
|
||||
break;
|
||||
case UNDEFINED:
|
||||
blob.writeByte(DebugConstants.FIELD_UNDEFINED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endClass() {
|
||||
if (phase == ClassPhase.STATIC_FIELDS) {
|
||||
blob.writeByte(DebugConstants.FIELD_END);
|
||||
}
|
||||
if (phase == ClassPhase.INSTANCE_FIELDS) {
|
||||
blob.writeByte(DebugConstants.FIELD_END_SEQUENCE);
|
||||
}
|
||||
++currentIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeInterface(String name, int address) {
|
||||
blob.writeByte(DebugConstants.CLASS_INTERFACE);
|
||||
blob.writeLEB(classes.classPtr(name));
|
||||
writeAddress(address);
|
||||
++currentIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writePrimitive(PrimitiveType type, int address) {
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
blob.writeLEB(DebugConstants.CLASS_BOOLEAN);
|
||||
break;
|
||||
case BYTE:
|
||||
blob.writeLEB(DebugConstants.CLASS_BYTE);
|
||||
break;
|
||||
case SHORT:
|
||||
blob.writeLEB(DebugConstants.CLASS_SHORT);
|
||||
break;
|
||||
case CHARACTER:
|
||||
blob.writeLEB(DebugConstants.CLASS_CHAR);
|
||||
break;
|
||||
case INTEGER:
|
||||
blob.writeLEB(DebugConstants.CLASS_INT);
|
||||
break;
|
||||
case LONG:
|
||||
blob.writeLEB(DebugConstants.CLASS_LONG);
|
||||
break;
|
||||
case FLOAT:
|
||||
blob.writeLEB(DebugConstants.CLASS_FLOAT);
|
||||
break;
|
||||
case DOUBLE:
|
||||
blob.writeLEB(DebugConstants.CLASS_DOUBLE);
|
||||
break;
|
||||
}
|
||||
writeAddress(address);
|
||||
++currentIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeArray(int itemType, int address) {
|
||||
blob.writeByte(DebugConstants.CLASS_ARRAY);
|
||||
blob.writeSLEB(currentIndex - itemType);
|
||||
writeAddress(address);
|
||||
++currentIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeUnknown(int address) {
|
||||
blob.writeByte(DebugConstants.CLASS_UNKNOWN);
|
||||
writeAddress(address);
|
||||
++currentIndex;
|
||||
}
|
||||
|
||||
private void writeAddress(int address) {
|
||||
blob.writeSLEB(address - currentAddress);
|
||||
currentAddress = address;
|
||||
}
|
||||
|
||||
private enum ClassPhase {
|
||||
NO_CLASS,
|
||||
STATIC_FIELDS,
|
||||
INSTANCE_FIELDS
|
||||
}
|
||||
}
|
|
@ -26,10 +26,39 @@ public final class DebugConstants {
|
|||
public static final int LOC_PTR = 4;
|
||||
public static final int LOC_USER = 10;
|
||||
|
||||
public static final int CLASS_ROOT = 0;
|
||||
public static final int CLASS_CLASS = 1;
|
||||
public static final int CLASS_INTERFACE = 2;
|
||||
public static final int CLASS_ARRAY = 3;
|
||||
public static final int CLASS_BOOLEAN = 4;
|
||||
public static final int CLASS_BYTE = 5;
|
||||
public static final int CLASS_SHORT = 6;
|
||||
public static final int CLASS_CHAR = 7;
|
||||
public static final int CLASS_INT = 8;
|
||||
public static final int CLASS_LONG = 9;
|
||||
public static final int CLASS_FLOAT = 10;
|
||||
public static final int CLASS_DOUBLE = 11;
|
||||
public static final int CLASS_UNKNOWN = 12;
|
||||
|
||||
public static final int FIELD_END = 0;
|
||||
public static final int FIELD_END_SEQUENCE = 1;
|
||||
public static final int FIELD_BOOLEAN = 2;
|
||||
public static final int FIELD_BYTE = 3;
|
||||
public static final int FIELD_SHORT = 4;
|
||||
public static final int FIELD_CHAR = 5;
|
||||
public static final int FIELD_INT = 6;
|
||||
public static final int FIELD_LONG = 7;
|
||||
public static final int FIELD_FLOAT = 8;
|
||||
public static final int FIELD_DOUBLE = 9;
|
||||
public static final int FIELD_OBJECT = 10;
|
||||
public static final int FIELD_ADDRESS = 11;
|
||||
public static final int FIELD_UNDEFINED = 12;
|
||||
|
||||
public static final String SECTION_STRINGS = "teavm_str";
|
||||
public static final String SECTION_FILES = "teavm_file";
|
||||
public static final String SECTION_PACKAGES = "teavm_pkg";
|
||||
public static final String SECTION_CLASSES = "teavm_cls";
|
||||
public static final String SECTION_CLASS_LAYOUT = "teavm_cll";
|
||||
public static final String SECTION_METHODS = "teavm_mtd";
|
||||
public static final String SECTION_LINES = "teavm_line";
|
||||
public static final String SECTION_VARIABLES = "teavm_var";
|
||||
|
|
|
@ -27,6 +27,7 @@ public class DebugInfoBuilder {
|
|||
private DebugMethodsBuilder methods;
|
||||
private DebugVariablesBuilder variables;
|
||||
private DebugLinesBuilder lines;
|
||||
private DebugClassLayoutBuilder classLayout;
|
||||
|
||||
public DebugInfoBuilder() {
|
||||
strings = new DebugStringsBuilder();
|
||||
|
@ -36,6 +37,7 @@ public class DebugInfoBuilder {
|
|||
methods = new DebugMethodsBuilder(classes, strings);
|
||||
variables = new DebugVariablesBuilder(strings);
|
||||
lines = new DebugLinesBuilder(files, methods);
|
||||
classLayout = new DebugClassLayoutBuilder(classes, strings);
|
||||
}
|
||||
|
||||
public DebugStrings strings() {
|
||||
|
@ -66,6 +68,10 @@ public class DebugInfoBuilder {
|
|||
return lines;
|
||||
}
|
||||
|
||||
public DebugClassLayout classLayout() {
|
||||
return classLayout;
|
||||
}
|
||||
|
||||
public List<WasmCustomSection> build() {
|
||||
var result = new ArrayList<WasmCustomSection>();
|
||||
addSection(result, strings);
|
||||
|
@ -75,6 +81,7 @@ public class DebugInfoBuilder {
|
|||
addSection(result, methods);
|
||||
addSection(result, variables);
|
||||
addSection(result, lines);
|
||||
addSection(result, classLayout);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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 interface ArrayLayout extends TypeLayout {
|
||||
TypeLayout elementType();
|
||||
|
||||
@Override
|
||||
default TypeLayoutKind kind() {
|
||||
return TypeLayoutKind.ARRAY;
|
||||
}
|
||||
}
|
|
@ -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.info;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface ClassLayout extends TypeLayout {
|
||||
ClassInfo classRef();
|
||||
|
||||
ClassLayout superclass();
|
||||
|
||||
Collection<? extends FieldInfo> instanceFields();
|
||||
|
||||
Collection<? extends FieldInfo> staticFields();
|
||||
|
||||
int size();
|
||||
|
||||
@Override
|
||||
default TypeLayoutKind kind() {
|
||||
return TypeLayoutKind.CLASS;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* 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 com.carrotsearch.hppc.IntObjectHashMap;
|
||||
import com.carrotsearch.hppc.IntObjectMap;
|
||||
import com.carrotsearch.hppc.ObjectIntHashMap;
|
||||
import com.carrotsearch.hppc.ObjectIntMap;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ClassLayoutInfo {
|
||||
private IntObjectMap<TypeLayout> layoutByAddress;
|
||||
|
||||
public abstract List<? extends TypeLayout> types();
|
||||
|
||||
public TypeLayout find(int address) {
|
||||
if (layoutByAddress == null) {
|
||||
layoutByAddress = new IntObjectHashMap<>();
|
||||
for (var typeLayout : types()) {
|
||||
layoutByAddress.put(typeLayout.address(), typeLayout);
|
||||
}
|
||||
}
|
||||
return layoutByAddress.get(address);
|
||||
}
|
||||
|
||||
public void dump(PrintStream out) {
|
||||
var indexes = new ObjectIntHashMap<TypeLayout>();
|
||||
for (var i = 0; i < types().size(); ++i) {
|
||||
indexes.put(types().get(i), i);
|
||||
}
|
||||
for (var i = 0; i < types().size(); ++i) {
|
||||
out.print("#" + i + ": ");
|
||||
var type = types().get(i);
|
||||
out.println(type.kind().name().toLowerCase());
|
||||
out.println(" address: " + Integer.toHexString(type.address()));
|
||||
switch (type.kind()) {
|
||||
case CLASS:
|
||||
dumpClass(out, indexes, (ClassLayout) type);
|
||||
break;
|
||||
case INTERFACE:
|
||||
dumpInterface(out, (InterfaceLayout) type);
|
||||
break;
|
||||
case ARRAY:
|
||||
dumpArray(out, indexes, (ArrayLayout) type);
|
||||
break;
|
||||
case PRIMITIVE:
|
||||
dumpPrimitive(out, (PrimitiveLayout) type);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void dumpClass(PrintStream out, ObjectIntMap<TypeLayout> indexes, ClassLayout cls) {
|
||||
out.println(" name: " + cls.classRef().fullName());
|
||||
out.println(" size: " + cls.size());
|
||||
if (cls.superclass() != null) {
|
||||
out.println(" superclass: #" + indexes.get(cls.superclass()));
|
||||
}
|
||||
if (!cls.staticFields().isEmpty()) {
|
||||
out.println(" static fields:");
|
||||
dumpFields(out, cls.staticFields());
|
||||
}
|
||||
if (!cls.instanceFields().isEmpty()) {
|
||||
out.println(" instance fields:");
|
||||
dumpFields(out, cls.instanceFields());
|
||||
}
|
||||
}
|
||||
|
||||
private static void dumpFields(PrintStream out, Collection<? extends FieldInfo> fields) {
|
||||
for (var field : fields) {
|
||||
out.println(" " + field.name() + ": ");
|
||||
out.println(" offset: " + Integer.toHexString(field.address()));
|
||||
out.println(" type: " + field.type().name().toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
private static void dumpInterface(PrintStream out, InterfaceLayout cls) {
|
||||
out.println(" name: " + cls.classRef().fullName());
|
||||
}
|
||||
|
||||
private static void dumpArray(PrintStream out, ObjectIntMap<TypeLayout> indexes, ArrayLayout array) {
|
||||
out.println(" element: #" + indexes.get(array.elementType()));
|
||||
}
|
||||
|
||||
private static void dumpPrimitive(PrintStream out, PrimitiveLayout primitive) {
|
||||
out.println(" primitive type: " + primitive.primitiveType().name().toLowerCase());
|
||||
}
|
||||
}
|
|
@ -21,12 +21,15 @@ public class DebugInfo {
|
|||
private VariablesInfo variables;
|
||||
private LineInfo lines;
|
||||
private ControlFlowInfo controlFlow;
|
||||
private ClassLayoutInfo classLayoutInfo;
|
||||
private int offset;
|
||||
|
||||
public DebugInfo(VariablesInfo variables, LineInfo lines, ControlFlowInfo controlFlow, int offset) {
|
||||
public DebugInfo(VariablesInfo variables, LineInfo lines, ControlFlowInfo controlFlow,
|
||||
ClassLayoutInfo classLayoutInfo, int offset) {
|
||||
this.variables = variables;
|
||||
this.lines = lines;
|
||||
this.controlFlow = controlFlow;
|
||||
this.classLayoutInfo = classLayoutInfo;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
|
@ -46,6 +49,10 @@ public class DebugInfo {
|
|||
return offset;
|
||||
}
|
||||
|
||||
public ClassLayoutInfo classLayoutInfo() {
|
||||
return classLayoutInfo;
|
||||
}
|
||||
|
||||
public void dump(PrintStream out) {
|
||||
if (offset != 0) {
|
||||
out.println("Code section offset: " + Integer.toHexString(offset));
|
||||
|
@ -62,5 +69,9 @@ public class DebugInfo {
|
|||
out.println("VARIABLES");
|
||||
variables.dump(out);
|
||||
}
|
||||
if (classLayoutInfo != null) {
|
||||
out.println("CLASS LAYOUT:");
|
||||
classLayoutInfo.dump(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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 FieldInfo {
|
||||
public abstract int address();
|
||||
|
||||
public abstract String name();
|
||||
|
||||
public abstract FieldType type();
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 FieldType {
|
||||
BOOLEAN,
|
||||
BYTE,
|
||||
SHORT,
|
||||
CHAR,
|
||||
INT,
|
||||
LONG,
|
||||
FLOAT,
|
||||
DOUBLE,
|
||||
OBJECT,
|
||||
ADDRESS,
|
||||
UNDEFINED
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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 interface InterfaceLayout extends TypeLayout {
|
||||
ClassInfo classRef();
|
||||
|
||||
@Override
|
||||
default TypeLayoutKind kind() {
|
||||
return TypeLayoutKind.INTERFACE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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 org.teavm.model.PrimitiveType;
|
||||
|
||||
public interface PrimitiveLayout extends TypeLayout {
|
||||
PrimitiveType primitiveType();
|
||||
|
||||
@Override
|
||||
default TypeLayoutKind kind() {
|
||||
return TypeLayoutKind.PRIMITIVE;
|
||||
}
|
||||
}
|
|
@ -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.info;
|
||||
|
||||
public interface TypeLayout {
|
||||
TypeLayoutKind kind();
|
||||
|
||||
int address();
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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 TypeLayoutKind {
|
||||
CLASS,
|
||||
INTERFACE,
|
||||
ARRAY,
|
||||
PRIMITIVE,
|
||||
UNKNOWN
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 interface UnknownLayout extends TypeLayout {
|
||||
@Override
|
||||
default TypeLayoutKind kind() {
|
||||
return TypeLayoutKind.UNKNOWN;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,400 @@
|
|||
/*
|
||||
* 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.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import org.teavm.backend.wasm.debug.DebugConstants;
|
||||
import org.teavm.backend.wasm.debug.info.ArrayLayout;
|
||||
import org.teavm.backend.wasm.debug.info.ClassInfo;
|
||||
import org.teavm.backend.wasm.debug.info.ClassLayout;
|
||||
import org.teavm.backend.wasm.debug.info.ClassLayoutInfo;
|
||||
import org.teavm.backend.wasm.debug.info.FieldInfo;
|
||||
import org.teavm.backend.wasm.debug.info.FieldType;
|
||||
import org.teavm.backend.wasm.debug.info.InterfaceLayout;
|
||||
import org.teavm.backend.wasm.debug.info.PrimitiveLayout;
|
||||
import org.teavm.backend.wasm.debug.info.TypeLayout;
|
||||
import org.teavm.backend.wasm.debug.info.UnknownLayout;
|
||||
import org.teavm.model.PrimitiveType;
|
||||
|
||||
public class DebugClassLayoutParser extends DebugSectionParser {
|
||||
private DebugStringParser strings;
|
||||
private DebugClassParser classes;
|
||||
private ArrayList<TypeLayoutImpl> types = new ArrayList<>();
|
||||
private List<List<Consumer<TypeLayoutImpl>>> forwardReferences = new ArrayList<>();
|
||||
private int lastAddress;
|
||||
private int lastFieldOffset;
|
||||
private ClassLayoutInfoImpl classLayoutInfo;
|
||||
|
||||
public DebugClassLayoutParser(DebugStringParser strings, DebugClassParser classes) {
|
||||
super(DebugConstants.SECTION_CLASS_LAYOUT, strings, classes);
|
||||
this.strings = strings;
|
||||
this.classes = classes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doParse() {
|
||||
while (ptr < data.length) {
|
||||
var kind = data[ptr++];
|
||||
switch (kind) {
|
||||
case DebugConstants.CLASS_ROOT:
|
||||
parseRootClass();
|
||||
break;
|
||||
case DebugConstants.CLASS_CLASS:
|
||||
parseClass();
|
||||
break;
|
||||
case DebugConstants.CLASS_INTERFACE:
|
||||
parseInterface();
|
||||
break;
|
||||
case DebugConstants.CLASS_ARRAY:
|
||||
parseArray();
|
||||
break;
|
||||
case DebugConstants.CLASS_BOOLEAN:
|
||||
parsePrimitive(PrimitiveType.BOOLEAN);
|
||||
break;
|
||||
case DebugConstants.CLASS_BYTE:
|
||||
parsePrimitive(PrimitiveType.BYTE);
|
||||
break;
|
||||
case DebugConstants.CLASS_SHORT:
|
||||
parsePrimitive(PrimitiveType.SHORT);
|
||||
break;
|
||||
case DebugConstants.CLASS_CHAR:
|
||||
parsePrimitive(PrimitiveType.CHARACTER);
|
||||
break;
|
||||
case DebugConstants.CLASS_INT:
|
||||
parsePrimitive(PrimitiveType.INTEGER);
|
||||
break;
|
||||
case DebugConstants.CLASS_LONG:
|
||||
parsePrimitive(PrimitiveType.LONG);
|
||||
break;
|
||||
case DebugConstants.CLASS_FLOAT:
|
||||
parsePrimitive(PrimitiveType.FLOAT);
|
||||
break;
|
||||
case DebugConstants.CLASS_DOUBLE:
|
||||
parsePrimitive(PrimitiveType.DOUBLE);
|
||||
break;
|
||||
case DebugConstants.CLASS_UNKNOWN:
|
||||
parseUnknown();
|
||||
break;
|
||||
}
|
||||
}
|
||||
types.trimToSize();
|
||||
classLayoutInfo = new ClassLayoutInfoImpl(Collections.unmodifiableList(types));
|
||||
}
|
||||
|
||||
public ClassLayoutInfo getInfo() {
|
||||
return classLayoutInfo;
|
||||
}
|
||||
|
||||
private void parseRootClass() {
|
||||
var classPtr = classes.getClass(readLEB());
|
||||
var address = readAddress();
|
||||
var size = readLEB();
|
||||
var type = new ClassLayoutImpl(address, classPtr, size);
|
||||
addType(type);
|
||||
parseClassFields(type);
|
||||
}
|
||||
|
||||
private void parseClass() {
|
||||
var classPtr = classes.getClass(readLEB());
|
||||
var superclassIndex = types.size() - readSignedLEB();
|
||||
var address = readAddress();
|
||||
var size = readLEB();
|
||||
var type = new ClassLayoutImpl(address, classPtr, size);
|
||||
addType(type);
|
||||
ref(superclassIndex, superclass -> type.superclass = (ClassLayoutImpl) superclass);
|
||||
parseClassFields(type);
|
||||
}
|
||||
|
||||
private void parseClassFields(ClassLayoutImpl type) {
|
||||
lastFieldOffset = 0;
|
||||
var staticFields = new ArrayList<FieldInfoImpl>();
|
||||
while (true) {
|
||||
var fieldType = data[ptr++];
|
||||
if (fieldType == DebugConstants.FIELD_END) {
|
||||
staticFields.trimToSize();
|
||||
type.staticFields = staticFields.isEmpty() ? Collections.emptyList()
|
||||
: Collections.unmodifiableList(staticFields);
|
||||
type.instanceFields = Collections.emptyList();
|
||||
return;
|
||||
}
|
||||
if (fieldType == DebugConstants.FIELD_END_SEQUENCE) {
|
||||
break;
|
||||
}
|
||||
staticFields.add(parseField(fieldType));
|
||||
}
|
||||
|
||||
lastFieldOffset = 0;
|
||||
var instanceFields = new ArrayList<FieldInfoImpl>();
|
||||
while (true) {
|
||||
var fieldType = data[ptr++];
|
||||
if (fieldType == DebugConstants.FIELD_END || fieldType == DebugConstants.FIELD_END_SEQUENCE) {
|
||||
break;
|
||||
}
|
||||
instanceFields.add(parseField(fieldType));
|
||||
}
|
||||
|
||||
staticFields.trimToSize();
|
||||
instanceFields.trimToSize();
|
||||
type.staticFields = staticFields.isEmpty() ? Collections.emptyList()
|
||||
: Collections.unmodifiableList(staticFields);
|
||||
type.instanceFields = instanceFields.isEmpty() ? Collections.emptyList()
|
||||
: Collections.unmodifiableList(instanceFields);
|
||||
}
|
||||
|
||||
private FieldInfoImpl parseField(byte type) {
|
||||
FieldType fieldType;
|
||||
switch (type) {
|
||||
case DebugConstants.FIELD_BOOLEAN:
|
||||
fieldType = FieldType.BOOLEAN;
|
||||
break;
|
||||
case DebugConstants.FIELD_BYTE:
|
||||
fieldType = FieldType.BYTE;
|
||||
break;
|
||||
case DebugConstants.FIELD_SHORT:
|
||||
fieldType = FieldType.SHORT;
|
||||
break;
|
||||
case DebugConstants.FIELD_CHAR:
|
||||
fieldType = FieldType.CHAR;
|
||||
break;
|
||||
case DebugConstants.FIELD_INT:
|
||||
fieldType = FieldType.INT;
|
||||
break;
|
||||
case DebugConstants.FIELD_LONG:
|
||||
fieldType = FieldType.LONG;
|
||||
break;
|
||||
case DebugConstants.FIELD_FLOAT:
|
||||
fieldType = FieldType.FLOAT;
|
||||
break;
|
||||
case DebugConstants.FIELD_DOUBLE:
|
||||
fieldType = FieldType.DOUBLE;
|
||||
break;
|
||||
case DebugConstants.FIELD_OBJECT:
|
||||
fieldType = FieldType.OBJECT;
|
||||
break;
|
||||
case DebugConstants.FIELD_ADDRESS:
|
||||
fieldType = FieldType.ADDRESS;
|
||||
break;
|
||||
default:
|
||||
fieldType = FieldType.UNDEFINED;
|
||||
break;
|
||||
}
|
||||
var name = strings.getString(readLEB());
|
||||
var offset = lastFieldOffset + readSignedLEB();
|
||||
lastFieldOffset = offset;
|
||||
return new FieldInfoImpl(offset, name, fieldType);
|
||||
}
|
||||
|
||||
private void parseInterface() {
|
||||
var classRef = classes.getClass(readLEB());
|
||||
var address = readAddress();
|
||||
addType(new InterfaceLayoutImpl(address, classRef));
|
||||
}
|
||||
|
||||
private void parseArray() {
|
||||
var elementPtr = types.size() - readSignedLEB();
|
||||
var address = readAddress();
|
||||
var type = new ArrayLayoutImpl(address);
|
||||
addType(type);
|
||||
ref(elementPtr, element -> type.elementType = element);
|
||||
}
|
||||
|
||||
private void parsePrimitive(PrimitiveType primitiveType) {
|
||||
var address = readAddress();
|
||||
addType(new PrimitiveLayoutImpl(address, primitiveType));
|
||||
}
|
||||
|
||||
private void parseUnknown() {
|
||||
var address = readAddress();
|
||||
addType(new UnknownLayoutImpl(address));
|
||||
}
|
||||
|
||||
private int readAddress() {
|
||||
var result = readSignedLEB() + lastAddress;
|
||||
lastAddress = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
private void addType(TypeLayoutImpl type) {
|
||||
var index = types.size();
|
||||
types.add(type);
|
||||
if (index < forwardReferences.size()) {
|
||||
var refs = forwardReferences.get(index);
|
||||
forwardReferences.set(index, null);
|
||||
for (var ref : refs) {
|
||||
ref.accept(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ref(int index, Consumer<TypeLayoutImpl> handler) {
|
||||
if (index < types.size()) {
|
||||
handler.accept(types.get(index));
|
||||
} else {
|
||||
if (index >= forwardReferences.size()) {
|
||||
forwardReferences.addAll(Collections.nCopies(index + 1 - forwardReferences.size(), null));
|
||||
}
|
||||
var refs = forwardReferences.get(index);
|
||||
if (refs == null) {
|
||||
refs = new ArrayList<>();
|
||||
forwardReferences.set(index, refs);
|
||||
}
|
||||
refs.add(handler);
|
||||
}
|
||||
}
|
||||
|
||||
private static abstract class TypeLayoutImpl implements TypeLayout {
|
||||
private int address;
|
||||
|
||||
private TypeLayoutImpl(int address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int address() {
|
||||
return address;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ClassLayoutImpl extends TypeLayoutImpl implements ClassLayout {
|
||||
private ClassInfo classRef;
|
||||
private List<? extends FieldInfoImpl> instanceFields;
|
||||
private List<? extends FieldInfoImpl> staticFields;
|
||||
private ClassLayoutImpl superclass;
|
||||
private int size;
|
||||
|
||||
ClassLayoutImpl(int address, ClassInfo classRef, int size) {
|
||||
super(address);
|
||||
this.classRef = classRef;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassInfo classRef() {
|
||||
return classRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLayout superclass() {
|
||||
return superclass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends FieldInfo> instanceFields() {
|
||||
return instanceFields;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends FieldInfo> staticFields() {
|
||||
return staticFields;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FieldInfoImpl extends FieldInfo {
|
||||
private int address;
|
||||
private String name;
|
||||
private FieldType type;
|
||||
|
||||
FieldInfoImpl(int address, String name, FieldType type) {
|
||||
this.address = address;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int address() {
|
||||
return address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldType type() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
private static class InterfaceLayoutImpl extends TypeLayoutImpl implements InterfaceLayout {
|
||||
private ClassInfo classRef;
|
||||
|
||||
InterfaceLayoutImpl(int address, ClassInfo classRef) {
|
||||
super(address);
|
||||
this.classRef = classRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassInfo classRef() {
|
||||
return classRef;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ArrayLayoutImpl extends TypeLayoutImpl implements ArrayLayout {
|
||||
private TypeLayoutImpl elementType;
|
||||
|
||||
ArrayLayoutImpl(int address) {
|
||||
super(address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeLayout elementType() {
|
||||
return elementType;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PrimitiveLayoutImpl extends TypeLayoutImpl implements PrimitiveLayout {
|
||||
private PrimitiveType primitiveType;
|
||||
|
||||
PrimitiveLayoutImpl(int address, PrimitiveType primitiveType) {
|
||||
super(address);
|
||||
this.primitiveType = primitiveType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrimitiveType primitiveType() {
|
||||
return primitiveType;
|
||||
}
|
||||
}
|
||||
|
||||
private static class UnknownLayoutImpl extends TypeLayoutImpl implements UnknownLayout {
|
||||
UnknownLayoutImpl(int address) {
|
||||
super(address);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ClassLayoutInfoImpl extends ClassLayoutInfo {
|
||||
private List<TypeLayoutImpl> types;
|
||||
|
||||
ClassLayoutInfoImpl(List<TypeLayoutImpl> types) {
|
||||
this.types = types;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends TypeLayout> types() {
|
||||
return types;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,6 +33,7 @@ public class DebugInfoParser extends ModuleParser {
|
|||
private DebugLinesParser lines;
|
||||
private DebugVariablesParser variables;
|
||||
private ControlFlowInfo controlFlow;
|
||||
private DebugClassLayoutParser classLayoutInfo;
|
||||
private int offset;
|
||||
|
||||
public DebugInfoParser(AsyncInputStream reader) {
|
||||
|
@ -44,6 +45,7 @@ public class DebugInfoParser extends ModuleParser {
|
|||
var methods = addSection(new DebugMethodParser(strings, classes));
|
||||
variables = addSection(new DebugVariablesParser(strings));
|
||||
lines = addSection(new DebugLinesParser(files, methods));
|
||||
classLayoutInfo = addSection(new DebugClassLayoutParser(strings, classes));
|
||||
}
|
||||
|
||||
private <T extends DebugSectionParser> T addSection(T section) {
|
||||
|
@ -52,7 +54,8 @@ public class DebugInfoParser extends ModuleParser {
|
|||
}
|
||||
|
||||
public DebugInfo getDebugInfo() {
|
||||
return new DebugInfo(variables.getVariablesInfo(), lines.getLineInfo(), controlFlow, offset);
|
||||
return new DebugInfo(variables.getVariablesInfo(), lines.getLineInfo(), controlFlow,
|
||||
classLayoutInfo.getInfo(), offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -31,6 +31,8 @@ import org.teavm.backend.wasm.binary.DataPrimitives;
|
|||
import org.teavm.backend.wasm.binary.DataStructure;
|
||||
import org.teavm.backend.wasm.binary.DataType;
|
||||
import org.teavm.backend.wasm.binary.DataValue;
|
||||
import org.teavm.backend.wasm.debug.DebugClassLayout;
|
||||
import org.teavm.backend.wasm.debug.info.FieldType;
|
||||
import org.teavm.common.IntegerArray;
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.Function;
|
||||
|
@ -415,16 +417,20 @@ public class WasmClassGenerator {
|
|||
if (type instanceof ValueType.Primitive) {
|
||||
return false;
|
||||
} else if (type instanceof ValueType.Object) {
|
||||
String className = ((ValueType.Object) type).getClassName();
|
||||
return !characteristics.isStructure(className)
|
||||
&& !characteristics.isFunction(className)
|
||||
&& !characteristics.isResource(className)
|
||||
&& !className.equals(Address.class.getName());
|
||||
var className = ((ValueType.Object) type).getClassName();
|
||||
return isManagedClass(className);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isManagedClass(String className) {
|
||||
return !characteristics.isStructure(className)
|
||||
&& !characteristics.isFunction(className)
|
||||
&& !characteristics.isResource(className)
|
||||
&& !className.equals(Address.class.getName());
|
||||
}
|
||||
|
||||
private void fillVirtualTable(VirtualTable vtable, DataValue array) {
|
||||
int index = 0;
|
||||
List<VirtualTable> tables = new ArrayList<>();
|
||||
|
@ -693,6 +699,105 @@ public class WasmClassGenerator {
|
|||
return cls.getMethod(new MethodDescriptor("<clinit>", ValueType.VOID)) != null;
|
||||
}
|
||||
|
||||
public void writeDebug(DebugClassLayout debug) {
|
||||
var list = new ArrayList<>(binaryDataMap.values());
|
||||
var indexes = new ObjectIntHashMap<ValueType>();
|
||||
for (var i = 0; i < list.size(); ++i) {
|
||||
indexes.put(list.get(i).type, i);
|
||||
}
|
||||
for (var i = 0; i < list.size(); ++i) {
|
||||
var data = list.get(i);
|
||||
if (data.type instanceof ValueType.Primitive) {
|
||||
debug.writePrimitive(((ValueType.Primitive) data.type).getKind(), data.start);
|
||||
} else if (data.type instanceof ValueType.Array) {
|
||||
var itemType = ((ValueType.Array) data.type).getItemType();
|
||||
debug.writeArray(indexes.get(itemType), data.start);
|
||||
} else if (data.type instanceof ValueType.Object) {
|
||||
var className = ((ValueType.Object) data.type).getClassName();
|
||||
if (isManagedClass(className)) {
|
||||
var parent = data.cls.getParent() != null
|
||||
? indexes.get(ValueType.object(data.cls.getParent()))
|
||||
: -1;
|
||||
if (data.isInferface) {
|
||||
debug.writeInterface(className, data.start);
|
||||
} else {
|
||||
debug.startClass(className, parent, data.start, data.size);
|
||||
var fields = getFieldsWithOffset(data);
|
||||
for (var entry : fields) {
|
||||
if (entry.field.hasModifier(ElementModifier.STATIC)) {
|
||||
debug.staticField(entry.field.getName(), entry.offset,
|
||||
asDebugType(entry.field.getType()));
|
||||
}
|
||||
}
|
||||
for (var entry : fields) {
|
||||
if (!entry.field.hasModifier(ElementModifier.STATIC)) {
|
||||
debug.instanceField(entry.field.getName(), entry.offset,
|
||||
asDebugType(entry.field.getType()));
|
||||
}
|
||||
}
|
||||
debug.endClass();
|
||||
}
|
||||
} else {
|
||||
debug.writeUnknown(data.start);
|
||||
}
|
||||
} else {
|
||||
debug.writeUnknown(data.start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<FieldWithOffset> getFieldsWithOffset(ClassBinaryData data) {
|
||||
var result = new ArrayList<FieldWithOffset>();
|
||||
for (var field : data.fieldLayout) {
|
||||
var fieldReader = data.cls.getField(field.key);
|
||||
result.add(new FieldWithOffset(fieldReader, field.value));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class FieldWithOffset {
|
||||
private FieldReader field;
|
||||
private int offset;
|
||||
|
||||
FieldWithOffset(FieldReader field, int offset) {
|
||||
this.field = field;
|
||||
this.offset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
private FieldType asDebugType(ValueType type) {
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) type).getKind()) {
|
||||
case BOOLEAN:
|
||||
return FieldType.BOOLEAN;
|
||||
case BYTE:
|
||||
return FieldType.BYTE;
|
||||
case SHORT:
|
||||
return FieldType.SHORT;
|
||||
case CHARACTER:
|
||||
return FieldType.CHAR;
|
||||
case INTEGER:
|
||||
return FieldType.INT;
|
||||
case LONG:
|
||||
return FieldType.LONG;
|
||||
case FLOAT:
|
||||
return FieldType.FLOAT;
|
||||
case DOUBLE:
|
||||
return FieldType.DOUBLE;
|
||||
default:
|
||||
return FieldType.UNDEFINED;
|
||||
}
|
||||
} else if (type instanceof ValueType.Object) {
|
||||
if (isManagedClass(((ValueType.Object) type).getClassName())) {
|
||||
return FieldType.OBJECT;
|
||||
} else {
|
||||
return FieldType.ADDRESS;
|
||||
}
|
||||
} else {
|
||||
return FieldType.OBJECT;
|
||||
}
|
||||
}
|
||||
|
||||
static class ClassBinaryData {
|
||||
ValueType type;
|
||||
int size;
|
||||
|
|
Loading…
Reference in New Issue
Block a user