mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
WASM: support stack traces
This commit is contained in:
parent
09b3f18a2c
commit
8330eae4ae
|
@ -21,10 +21,14 @@ import java.util.Map;
|
||||||
import org.teavm.classlib.impl.DeclaringClassMetadataGenerator;
|
import org.teavm.classlib.impl.DeclaringClassMetadataGenerator;
|
||||||
import org.teavm.classlib.java.lang.annotation.TAnnotation;
|
import org.teavm.classlib.java.lang.annotation.TAnnotation;
|
||||||
import org.teavm.classlib.java.lang.reflect.TAnnotatedElement;
|
import org.teavm.classlib.java.lang.reflect.TAnnotatedElement;
|
||||||
|
import org.teavm.interop.Address;
|
||||||
|
import org.teavm.interop.DelegateTo;
|
||||||
import org.teavm.platform.Platform;
|
import org.teavm.platform.Platform;
|
||||||
import org.teavm.platform.PlatformClass;
|
import org.teavm.platform.PlatformClass;
|
||||||
import org.teavm.platform.metadata.ClassResource;
|
import org.teavm.platform.metadata.ClassResource;
|
||||||
import org.teavm.platform.metadata.ClassScopedMetadataProvider;
|
import org.teavm.platform.metadata.ClassScopedMetadataProvider;
|
||||||
|
import org.teavm.runtime.RuntimeClass;
|
||||||
|
import org.teavm.runtime.RuntimeJavaObject;
|
||||||
|
|
||||||
public class TClass<T> extends TObject implements TAnnotatedElement {
|
public class TClass<T> extends TObject implements TAnnotatedElement {
|
||||||
TString name;
|
TString name;
|
||||||
|
@ -61,6 +65,7 @@ public class TClass<T> extends TObject implements TAnnotatedElement {
|
||||||
return Platform.isAssignable(obj.getPlatformClass(), platformClass);
|
return Platform.isAssignable(obj.getPlatformClass(), platformClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DelegateTo("getNameLowLevel")
|
||||||
public TString getName() {
|
public TString getName() {
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
name = TString.wrap(Platform.getName(platformClass));
|
name = TString.wrap(Platform.getName(platformClass));
|
||||||
|
@ -68,6 +73,11 @@ public class TClass<T> extends TObject implements TAnnotatedElement {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private RuntimeJavaObject getNameLowLevel() {
|
||||||
|
RuntimeClass runtimeClass = Address.ofObject(this).toStructure();
|
||||||
|
return runtimeClass.name;
|
||||||
|
}
|
||||||
|
|
||||||
public TString getSimpleName() {
|
public TString getSimpleName() {
|
||||||
if (simpleName == null) {
|
if (simpleName == null) {
|
||||||
if (isArray()) {
|
if (isArray()) {
|
||||||
|
|
|
@ -19,10 +19,6 @@ import java.util.Objects;
|
||||||
import org.teavm.classlib.java.io.TSerializable;
|
import org.teavm.classlib.java.io.TSerializable;
|
||||||
import org.teavm.classlib.java.util.TObjects;
|
import org.teavm.classlib.java.util.TObjects;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public final class TStackTraceElement extends TObject implements TSerializable {
|
public final class TStackTraceElement extends TObject implements TSerializable {
|
||||||
private TString declaringClass;
|
private TString declaringClass;
|
||||||
private TString methodName;
|
private TString methodName;
|
||||||
|
@ -89,6 +85,7 @@ public final class TStackTraceElement extends TObject implements TSerializable {
|
||||||
} else {
|
} else {
|
||||||
sb.append(TString.wrap("Unknown Source"));
|
sb.append(TString.wrap("Unknown Source"));
|
||||||
}
|
}
|
||||||
|
sb.append(TString.wrap(")"));
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,11 @@ package org.teavm.classlib.java.lang;
|
||||||
|
|
||||||
import org.teavm.classlib.java.io.TPrintStream;
|
import org.teavm.classlib.java.io.TPrintStream;
|
||||||
import org.teavm.classlib.java.util.TArrays;
|
import org.teavm.classlib.java.util.TArrays;
|
||||||
|
import org.teavm.interop.DelegateTo;
|
||||||
import org.teavm.interop.Remove;
|
import org.teavm.interop.Remove;
|
||||||
import org.teavm.interop.Rename;
|
import org.teavm.interop.Rename;
|
||||||
import org.teavm.interop.Superclass;
|
import org.teavm.interop.Superclass;
|
||||||
|
import org.teavm.runtime.ExceptionHandling;
|
||||||
|
|
||||||
@Superclass("java.lang.Object")
|
@Superclass("java.lang.Object")
|
||||||
public class TThrowable extends RuntimeException {
|
public class TThrowable extends RuntimeException {
|
||||||
|
@ -29,6 +31,7 @@ public class TThrowable extends RuntimeException {
|
||||||
private boolean suppressionEnabled;
|
private boolean suppressionEnabled;
|
||||||
private boolean writableStackTrace;
|
private boolean writableStackTrace;
|
||||||
private TThrowable[] suppressed = new TThrowable[0];
|
private TThrowable[] suppressed = new TThrowable[0];
|
||||||
|
private TStackTraceElement[] stackTrace;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Rename("fakeInit")
|
@Rename("fakeInit")
|
||||||
|
@ -97,10 +100,18 @@ public class TThrowable extends RuntimeException {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@DelegateTo("fillInStackTraceLowLevel")
|
||||||
public Throwable fillInStackTrace() {
|
public Throwable fillInStackTrace() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TThrowable fillInStackTraceLowLevel() {
|
||||||
|
int stackSize = ExceptionHandling.callStackSize() - 1;
|
||||||
|
stackTrace = new TStackTraceElement[stackSize];
|
||||||
|
ExceptionHandling.fillStackTrace((StackTraceElement[]) (Object) stackTrace, 2);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Rename("getMessage")
|
@Rename("getMessage")
|
||||||
public TString getMessage0() {
|
public TString getMessage0() {
|
||||||
return message;
|
return message;
|
||||||
|
@ -143,15 +154,25 @@ public class TThrowable extends RuntimeException {
|
||||||
|
|
||||||
public void printStackTrace(TPrintStream stream) {
|
public void printStackTrace(TPrintStream stream) {
|
||||||
stream.println(TString.wrap(getClass().getName() + ": " + getMessage()));
|
stream.println(TString.wrap(getClass().getName() + ": " + getMessage()));
|
||||||
|
if (stackTrace != null) {
|
||||||
|
for (TStackTraceElement element : stackTrace) {
|
||||||
|
stream.print(TString.wrap(" at "));
|
||||||
|
stream.println(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cause != null && cause != this) {
|
||||||
|
stream.print(TString.wrap("Caused by: "));
|
||||||
|
cause.printStackTrace(stream);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Rename("getStackTrace")
|
@Rename("getStackTrace")
|
||||||
public TStackTraceElement[] getStackTrace0() {
|
public TStackTraceElement[] getStackTrace0() {
|
||||||
return new TStackTraceElement[0];
|
return stackTrace != null ? stackTrace.clone() : new TStackTraceElement[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStackTrace(@SuppressWarnings("unused") TStackTraceElement[] stackTrace) {
|
public void setStackTrace(@SuppressWarnings("unused") TStackTraceElement[] stackTrace) {
|
||||||
// do nothing
|
this.stackTrace = stackTrace.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Rename("getSuppressed")
|
@Rename("getSuppressed")
|
||||||
|
|
|
@ -282,7 +282,7 @@ public class WasmTarget implements TeaVMTarget {
|
||||||
|
|
||||||
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
||||||
new HashSet<>());
|
new HashSet<>());
|
||||||
WasmStringPool stringPool = new WasmStringPool(classGenerator, binaryWriter);
|
WasmStringPool stringPool = classGenerator.getStringPool();
|
||||||
WasmGenerationContext context = new WasmGenerationContext(classes, module, controller.getDiagnostics(),
|
WasmGenerationContext context = new WasmGenerationContext(classes, module, controller.getDiagnostics(),
|
||||||
vtableProvider, tagRegistry, stringPool);
|
vtableProvider, tagRegistry, stringPool);
|
||||||
|
|
||||||
|
@ -302,7 +302,7 @@ public class WasmTarget implements TeaVMTarget {
|
||||||
context.addIntrinsic(mutatorIntrinsic);
|
context.addIntrinsic(mutatorIntrinsic);
|
||||||
context.addIntrinsic(new ShadowStackIntrinsic());
|
context.addIntrinsic(new ShadowStackIntrinsic());
|
||||||
ExceptionHandlingIntrinsic exceptionHandlingIntrinsic = new ExceptionHandlingIntrinsic(binaryWriter,
|
ExceptionHandlingIntrinsic exceptionHandlingIntrinsic = new ExceptionHandlingIntrinsic(binaryWriter,
|
||||||
classGenerator);
|
classGenerator, stringPool);
|
||||||
context.addIntrinsic(exceptionHandlingIntrinsic);
|
context.addIntrinsic(exceptionHandlingIntrinsic);
|
||||||
|
|
||||||
WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator, binaryWriter);
|
WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator, binaryWriter);
|
||||||
|
|
|
@ -16,34 +16,50 @@
|
||||||
package org.teavm.backend.wasm.generate;
|
package org.teavm.backend.wasm.generate;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import org.teavm.backend.wasm.binary.BinaryWriter;
|
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||||
import org.teavm.backend.wasm.binary.DataPrimitives;
|
import org.teavm.backend.wasm.binary.DataPrimitives;
|
||||||
import org.teavm.backend.wasm.binary.DataStructure;
|
import org.teavm.backend.wasm.binary.DataStructure;
|
||||||
import org.teavm.backend.wasm.binary.DataValue;
|
import org.teavm.backend.wasm.binary.DataValue;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
import org.teavm.model.lowlevel.CallSiteDescriptor;
|
import org.teavm.model.lowlevel.CallSiteDescriptor;
|
||||||
|
import org.teavm.model.lowlevel.CallSiteLocation;
|
||||||
import org.teavm.model.lowlevel.ExceptionHandlerDescriptor;
|
import org.teavm.model.lowlevel.ExceptionHandlerDescriptor;
|
||||||
|
|
||||||
public class CallSiteBinaryGenerator {
|
public class CallSiteBinaryGenerator {
|
||||||
private static final int CALL_SITE_HANDLER_COUNT = 0;
|
private static final int CALL_SITE_HANDLER_COUNT = 0;
|
||||||
private static final int CALL_SITE_FIRST_HANDLER = 1;
|
private static final int CALL_SITE_FIRST_HANDLER = 1;
|
||||||
|
private static final int CALL_SITE_LOCATION = 2;
|
||||||
private static final int EXCEPTION_HANDLER_ID = 0;
|
private static final int EXCEPTION_HANDLER_ID = 0;
|
||||||
private static final int EXCEPTION_HANDLER_CLASS = 1;
|
private static final int EXCEPTION_HANDLER_CLASS = 1;
|
||||||
|
private static final int LOCATION_FILE = 0;
|
||||||
|
private static final int LOCATION_CLASS = 1;
|
||||||
|
private static final int LOCATION_METHOD = 2;
|
||||||
|
private static final int LOCATION_LINE_NUMBER = 3;
|
||||||
|
|
||||||
private DataStructure callSiteStructure = new DataStructure((byte) 0,
|
private DataStructure callSiteStructure = new DataStructure((byte) 0,
|
||||||
DataPrimitives.INT,
|
DataPrimitives.INT,
|
||||||
|
DataPrimitives.ADDRESS,
|
||||||
DataPrimitives.ADDRESS);
|
DataPrimitives.ADDRESS);
|
||||||
private DataStructure exceptionHandlerStructure = new DataStructure((byte) 0,
|
private DataStructure exceptionHandlerStructure = new DataStructure((byte) 0,
|
||||||
DataPrimitives.INT,
|
DataPrimitives.INT,
|
||||||
DataPrimitives.ADDRESS);
|
DataPrimitives.ADDRESS);
|
||||||
|
private DataStructure locationStructure = new DataStructure((byte) 0,
|
||||||
|
DataPrimitives.ADDRESS,
|
||||||
|
DataPrimitives.ADDRESS,
|
||||||
|
DataPrimitives.ADDRESS,
|
||||||
|
DataPrimitives.INT);
|
||||||
|
|
||||||
private BinaryWriter writer;
|
private BinaryWriter writer;
|
||||||
private WasmClassGenerator classGenerator;
|
private WasmClassGenerator classGenerator;
|
||||||
|
private WasmStringPool stringPool;
|
||||||
|
|
||||||
public CallSiteBinaryGenerator(BinaryWriter writer, WasmClassGenerator classGenerator) {
|
public CallSiteBinaryGenerator(BinaryWriter writer, WasmClassGenerator classGenerator, WasmStringPool stringPool) {
|
||||||
this.writer = writer;
|
this.writer = writer;
|
||||||
this.classGenerator = classGenerator;
|
this.classGenerator = classGenerator;
|
||||||
|
this.stringPool = stringPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int writeCallSites(List<CallSiteDescriptor> callSites) {
|
public int writeCallSites(List<CallSiteDescriptor> callSites) {
|
||||||
|
@ -53,7 +69,7 @@ public class CallSiteBinaryGenerator {
|
||||||
|
|
||||||
int firstCallSite = -1;
|
int firstCallSite = -1;
|
||||||
List<DataValue> binaryCallSites = new ArrayList<>();
|
List<DataValue> binaryCallSites = new ArrayList<>();
|
||||||
for (CallSiteDescriptor callSite : callSites) {
|
for (int i = 0; i < callSites.size(); i++) {
|
||||||
DataValue binaryCallSite = callSiteStructure.createValue();
|
DataValue binaryCallSite = callSiteStructure.createValue();
|
||||||
int address = writer.append(binaryCallSite);
|
int address = writer.append(binaryCallSite);
|
||||||
if (firstCallSite < 0) {
|
if (firstCallSite < 0) {
|
||||||
|
@ -62,6 +78,8 @@ public class CallSiteBinaryGenerator {
|
||||||
binaryCallSites.add(binaryCallSite);
|
binaryCallSites.add(binaryCallSite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<CallSiteLocation, Integer> locationCache = new HashMap<>();
|
||||||
|
|
||||||
for (int callSiteId = 0; callSiteId < callSites.size(); ++callSiteId) {
|
for (int callSiteId = 0; callSiteId < callSites.size(); ++callSiteId) {
|
||||||
DataValue binaryCallSite = binaryCallSites.get(callSiteId);
|
DataValue binaryCallSite = binaryCallSites.get(callSiteId);
|
||||||
CallSiteDescriptor callSite = callSites.get(callSiteId);
|
CallSiteDescriptor callSite = callSites.get(callSiteId);
|
||||||
|
@ -91,6 +109,23 @@ public class CallSiteBinaryGenerator {
|
||||||
binaryExceptionHandler.setAddress(EXCEPTION_HANDLER_CLASS, classPointer);
|
binaryExceptionHandler.setAddress(EXCEPTION_HANDLER_CLASS, classPointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int locationAddress = locationCache.computeIfAbsent(callSite.getLocation(), location -> {
|
||||||
|
DataValue binaryLocation = locationStructure.createValue();
|
||||||
|
int address = writer.append(binaryLocation);
|
||||||
|
if (location.getFileName() != null) {
|
||||||
|
binaryLocation.setAddress(LOCATION_FILE, stringPool.getStringPointer(location.getFileName()));
|
||||||
|
}
|
||||||
|
if (location.getClassName() != null) {
|
||||||
|
binaryLocation.setAddress(LOCATION_CLASS, stringPool.getStringPointer(location.getClassName()));
|
||||||
|
}
|
||||||
|
if (location.getMethodName() != null) {
|
||||||
|
binaryLocation.setAddress(LOCATION_METHOD, stringPool.getStringPointer(location.getMethodName()));
|
||||||
|
}
|
||||||
|
binaryLocation.setInt(LOCATION_LINE_NUMBER, location.getLineNumber());
|
||||||
|
return address;
|
||||||
|
});
|
||||||
|
binaryCallSite.setAddress(CALL_SITE_LOCATION, locationAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
return firstCallSite;
|
return firstCallSite;
|
||||||
|
|
|
@ -57,6 +57,7 @@ public class WasmClassGenerator {
|
||||||
private List<String> functionTable = new ArrayList<>();
|
private List<String> functionTable = new ArrayList<>();
|
||||||
private VirtualTableProvider vtableProvider;
|
private VirtualTableProvider vtableProvider;
|
||||||
private TagRegistry tagRegistry;
|
private TagRegistry tagRegistry;
|
||||||
|
private WasmStringPool stringPool;
|
||||||
private DataStructure objectStructure = new DataStructure((byte) 0,
|
private DataStructure objectStructure = new DataStructure((byte) 0,
|
||||||
DataPrimitives.INT, /* class */
|
DataPrimitives.INT, /* class */
|
||||||
DataPrimitives.ADDRESS /* monitor/hash code */);
|
DataPrimitives.ADDRESS /* monitor/hash code */);
|
||||||
|
@ -67,6 +68,7 @@ public class WasmClassGenerator {
|
||||||
DataPrimitives.INT, /* flags */
|
DataPrimitives.INT, /* flags */
|
||||||
DataPrimitives.INT, /* tag */
|
DataPrimitives.INT, /* tag */
|
||||||
DataPrimitives.INT, /* canary */
|
DataPrimitives.INT, /* canary */
|
||||||
|
DataPrimitives.ADDRESS, /* name */
|
||||||
DataPrimitives.ADDRESS, /* item type */
|
DataPrimitives.ADDRESS, /* item type */
|
||||||
DataPrimitives.ADDRESS, /* array type */
|
DataPrimitives.ADDRESS, /* array type */
|
||||||
DataPrimitives.INT, /* isInstance function */
|
DataPrimitives.INT, /* isInstance function */
|
||||||
|
@ -79,11 +81,12 @@ public class WasmClassGenerator {
|
||||||
private static final int CLASS_FLAGS = 2;
|
private static final int CLASS_FLAGS = 2;
|
||||||
private static final int CLASS_TAG = 3;
|
private static final int CLASS_TAG = 3;
|
||||||
private static final int CLASS_CANARY = 4;
|
private static final int CLASS_CANARY = 4;
|
||||||
private static final int CLASS_ITEM_TYPE = 5;
|
private static final int CLASS_NAME = 5;
|
||||||
private static final int CLASS_ARRAY_TYPE = 6;
|
private static final int CLASS_ITEM_TYPE = 6;
|
||||||
private static final int CLASS_IS_INSTANCE = 7;
|
private static final int CLASS_ARRAY_TYPE = 7;
|
||||||
private static final int CLASS_PARENT = 8;
|
private static final int CLASS_IS_INSTANCE = 8;
|
||||||
private static final int CLASS_LAYOUT = 9;
|
private static final int CLASS_PARENT = 9;
|
||||||
|
private static final int CLASS_LAYOUT = 10;
|
||||||
|
|
||||||
public WasmClassGenerator(ClassReaderSource classSource, VirtualTableProvider vtableProvider,
|
public WasmClassGenerator(ClassReaderSource classSource, VirtualTableProvider vtableProvider,
|
||||||
TagRegistry tagRegistry, BinaryWriter binaryWriter) {
|
TagRegistry tagRegistry, BinaryWriter binaryWriter) {
|
||||||
|
@ -91,6 +94,11 @@ public class WasmClassGenerator {
|
||||||
this.vtableProvider = vtableProvider;
|
this.vtableProvider = vtableProvider;
|
||||||
this.tagRegistry = tagRegistry;
|
this.tagRegistry = tagRegistry;
|
||||||
this.binaryWriter = binaryWriter;
|
this.binaryWriter = binaryWriter;
|
||||||
|
this.stringPool = new WasmStringPool(this, binaryWriter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmStringPool getStringPool() {
|
||||||
|
return stringPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addClass(ValueType type) {
|
private void addClass(ValueType type) {
|
||||||
|
@ -204,6 +212,7 @@ public class WasmClassGenerator {
|
||||||
int tag = ranges.stream().mapToInt(range -> range.lower).min().orElse(0);
|
int tag = ranges.stream().mapToInt(range -> range.lower).min().orElse(0);
|
||||||
header.setInt(CLASS_TAG, tag);
|
header.setInt(CLASS_TAG, tag);
|
||||||
header.setInt(CLASS_CANARY, RuntimeClass.computeCanary(occupiedSize, tag));
|
header.setInt(CLASS_CANARY, RuntimeClass.computeCanary(occupiedSize, tag));
|
||||||
|
header.setAddress(CLASS_NAME, stringPool.getStringPointer(name));
|
||||||
header.setInt(CLASS_IS_INSTANCE, functionTable.size());
|
header.setInt(CLASS_IS_INSTANCE, functionTable.size());
|
||||||
functionTable.add(WasmMangling.mangleIsSupertype(ValueType.object(name)));
|
functionTable.add(WasmMangling.mangleIsSupertype(ValueType.object(name)));
|
||||||
header.setAddress(CLASS_PARENT, parentPtr);
|
header.setAddress(CLASS_PARENT, parentPtr);
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.teavm.ast.InvocationExpr;
|
||||||
import org.teavm.backend.wasm.binary.BinaryWriter;
|
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||||
import org.teavm.backend.wasm.generate.CallSiteBinaryGenerator;
|
import org.teavm.backend.wasm.generate.CallSiteBinaryGenerator;
|
||||||
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
||||||
|
import org.teavm.backend.wasm.generate.WasmStringPool;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||||
|
@ -28,14 +29,18 @@ import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.lowlevel.CallSiteDescriptor;
|
import org.teavm.model.lowlevel.CallSiteDescriptor;
|
||||||
|
import org.teavm.runtime.CallSite;
|
||||||
import org.teavm.runtime.ExceptionHandling;
|
import org.teavm.runtime.ExceptionHandling;
|
||||||
|
|
||||||
public class ExceptionHandlingIntrinsic implements WasmIntrinsic {
|
public class ExceptionHandlingIntrinsic implements WasmIntrinsic {
|
||||||
private CallSiteBinaryGenerator callSiteBinaryGenerator;
|
private CallSiteBinaryGenerator callSiteBinaryGenerator;
|
||||||
|
private WasmClassGenerator classGenerator;
|
||||||
private List<WasmInt32Constant> constants = new ArrayList<>();
|
private List<WasmInt32Constant> constants = new ArrayList<>();
|
||||||
|
|
||||||
public ExceptionHandlingIntrinsic(BinaryWriter binaryWriter, WasmClassGenerator classGenerator) {
|
public ExceptionHandlingIntrinsic(BinaryWriter binaryWriter, WasmClassGenerator classGenerator,
|
||||||
callSiteBinaryGenerator = new CallSiteBinaryGenerator(binaryWriter, classGenerator);
|
WasmStringPool stringPool) {
|
||||||
|
callSiteBinaryGenerator = new CallSiteBinaryGenerator(binaryWriter, classGenerator, stringPool);
|
||||||
|
this.classGenerator = classGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -63,9 +68,10 @@ public class ExceptionHandlingIntrinsic implements WasmIntrinsic {
|
||||||
constant.setLocation(invocation.getLocation());
|
constant.setLocation(invocation.getLocation());
|
||||||
constants.add(constant);
|
constants.add(constant);
|
||||||
|
|
||||||
|
int callSiteSize = classGenerator.getClassSize(CallSite.class.getName());
|
||||||
WasmExpression id = manager.generate(invocation.getArguments().get(0));
|
WasmExpression id = manager.generate(invocation.getArguments().get(0));
|
||||||
WasmExpression offset = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL,
|
WasmExpression offset = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.MUL,
|
||||||
id, new WasmInt32Constant(3));
|
id, new WasmInt32Constant(callSiteSize));
|
||||||
|
|
||||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, constant, offset);
|
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, constant, offset);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,15 +21,21 @@ import java.util.List;
|
||||||
public class CallSiteDescriptor {
|
public class CallSiteDescriptor {
|
||||||
private int id;
|
private int id;
|
||||||
private List<ExceptionHandlerDescriptor> handlers = new ArrayList<>();
|
private List<ExceptionHandlerDescriptor> handlers = new ArrayList<>();
|
||||||
|
private CallSiteLocation location;
|
||||||
|
|
||||||
public CallSiteDescriptor(int id) {
|
public CallSiteDescriptor(int id, CallSiteLocation location) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
this.location = location;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CallSiteLocation getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
public List<ExceptionHandlerDescriptor> getHandlers() {
|
public List<ExceptionHandlerDescriptor> getHandlers() {
|
||||||
return handlers;
|
return handlers;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 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.model.lowlevel;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class CallSiteLocation {
|
||||||
|
private String fileName;
|
||||||
|
private String className;
|
||||||
|
private String methodName;
|
||||||
|
private int lineNumber;
|
||||||
|
|
||||||
|
public CallSiteLocation(String fileName, String className, String methodName, int lineNumber) {
|
||||||
|
this.fileName = fileName;
|
||||||
|
this.className = className;
|
||||||
|
this.methodName = methodName;
|
||||||
|
this.lineNumber = lineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileName() {
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClassName() {
|
||||||
|
return className;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMethodName() {
|
||||||
|
return methodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLineNumber() {
|
||||||
|
return lineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof CallSiteLocation)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CallSiteLocation other = (CallSiteLocation) obj;
|
||||||
|
return Objects.equals(fileName, other.fileName) && Objects.equals(className, other.className)
|
||||||
|
&& Objects.equals(methodName, other.methodName) && lineNumber == other.lineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(fileName, className, methodName, lineNumber);
|
||||||
|
}
|
||||||
|
}
|
|
@ -190,7 +190,11 @@ public class ExceptionHandlingShadowStackContributor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CallSiteDescriptor callSite = new CallSiteDescriptor(callSites.size());
|
String fileName = insn.getLocation() != null ? insn.getLocation().getFileName() : null;
|
||||||
|
int lineNumber = insn.getLocation() != null ? insn.getLocation().getLine() : -1;
|
||||||
|
CallSiteLocation location = new CallSiteLocation(fileName, method.getClassName(), method.getName(),
|
||||||
|
lineNumber);
|
||||||
|
CallSiteDescriptor callSite = new CallSiteDescriptor(callSites.size(), location);
|
||||||
callSites.add(callSite);
|
callSites.add(callSite);
|
||||||
List<Instruction> pre = setLocation(getInstructionsBeforeCallSite(callSite), insn.getLocation());
|
List<Instruction> pre = setLocation(getInstructionsBeforeCallSite(callSite), insn.getLocation());
|
||||||
List<Instruction> post = getInstructionsAfterCallSite(block, next, callSite, currentJointSources);
|
List<Instruction> post = getInstructionsAfterCallSite(block, next, callSite, currentJointSources);
|
||||||
|
|
|
@ -24,4 +24,5 @@ import org.teavm.interop.Unmanaged;
|
||||||
public class CallSite extends Structure {
|
public class CallSite extends Structure {
|
||||||
public int handlerCount;
|
public int handlerCount;
|
||||||
public ExceptionHandler firstHandler;
|
public ExceptionHandler firstHandler;
|
||||||
|
public CallSiteLocation location;
|
||||||
}
|
}
|
||||||
|
|
25
core/src/main/java/org/teavm/runtime/CallSiteLocation.java
Normal file
25
core/src/main/java/org/teavm/runtime/CallSiteLocation.java
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 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.runtime;
|
||||||
|
|
||||||
|
import org.teavm.interop.Structure;
|
||||||
|
|
||||||
|
public class CallSiteLocation extends Structure {
|
||||||
|
public String fileName;
|
||||||
|
public String className;
|
||||||
|
public String methodName;
|
||||||
|
public int lineNumber;
|
||||||
|
}
|
|
@ -21,7 +21,6 @@ import org.teavm.interop.StaticInit;
|
||||||
import org.teavm.interop.Structure;
|
import org.teavm.interop.Structure;
|
||||||
import org.teavm.interop.Unmanaged;
|
import org.teavm.interop.Unmanaged;
|
||||||
|
|
||||||
@Unmanaged
|
|
||||||
@StaticInit
|
@StaticInit
|
||||||
public final class ExceptionHandling {
|
public final class ExceptionHandling {
|
||||||
private ExceptionHandling() {
|
private ExceptionHandling() {
|
||||||
|
@ -32,12 +31,14 @@ public final class ExceptionHandling {
|
||||||
private static Throwable thrownException;
|
private static Throwable thrownException;
|
||||||
|
|
||||||
@Export(name = "sys$catchException")
|
@Export(name = "sys$catchException")
|
||||||
|
@Unmanaged
|
||||||
public static Throwable catchException() {
|
public static Throwable catchException() {
|
||||||
Throwable exception = thrownException;
|
Throwable exception = thrownException;
|
||||||
thrownException = null;
|
thrownException = null;
|
||||||
return exception;
|
return exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Unmanaged
|
||||||
public static void throwException(Throwable exception) {
|
public static void throwException(Throwable exception) {
|
||||||
thrownException = exception;
|
thrownException = exception;
|
||||||
|
|
||||||
|
@ -64,4 +65,41 @@ public final class ExceptionHandling {
|
||||||
stackFrame = ShadowStack.getNextStackFrame(stackFrame);
|
stackFrame = ShadowStack.getNextStackFrame(stackFrame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Unmanaged
|
||||||
|
public static int callStackSize() {
|
||||||
|
Address stackFrame = ShadowStack.getStackTop();
|
||||||
|
int size = 0;
|
||||||
|
while (stackFrame != null) {
|
||||||
|
stackFrame = ShadowStack.getNextStackFrame(stackFrame);
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unmanaged
|
||||||
|
public static void fillStackTrace(StackTraceElement[] target, int skip) {
|
||||||
|
Address stackFrame = ShadowStack.getNextStackFrame(ShadowStack.getNextStackFrame(ShadowStack.getStackTop()));
|
||||||
|
int index = 0;
|
||||||
|
while (stackFrame != null && index < target.length) {
|
||||||
|
int callSiteId = ShadowStack.getCallSiteId(stackFrame);
|
||||||
|
CallSite callSite = findCallSiteById(callSiteId);
|
||||||
|
CallSiteLocation location = callSite.location;
|
||||||
|
StackTraceElement element = createElement(location != null ? location.className : "",
|
||||||
|
location != null ? location.methodName : "", location != null ? location.fileName : null,
|
||||||
|
location != null ? location.lineNumber : -1);
|
||||||
|
if (skip > 0) {
|
||||||
|
skip--;
|
||||||
|
} else {
|
||||||
|
target[index++] = element;
|
||||||
|
}
|
||||||
|
|
||||||
|
stackFrame = ShadowStack.getNextStackFrame(stackFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static StackTraceElement createElement(String className, String methodName, String fileName,
|
||||||
|
int lineNumber) {
|
||||||
|
return new StackTraceElement(className, methodName, fileName, lineNumber);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ public class RuntimeClass extends RuntimeJavaObject {
|
||||||
public int flags;
|
public int flags;
|
||||||
public int tag;
|
public int tag;
|
||||||
public int canary;
|
public int canary;
|
||||||
|
public RuntimeJavaObject name;
|
||||||
public RuntimeClass itemType;
|
public RuntimeClass itemType;
|
||||||
public RuntimeClass arrayType;
|
public RuntimeClass arrayType;
|
||||||
public IsSupertypeFunction isSupertypeOf;
|
public IsSupertypeFunction isSupertypeOf;
|
||||||
|
|
|
@ -172,7 +172,6 @@ public final class Platform {
|
||||||
return cls.itemType;
|
return cls.itemType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@DelegateTo("getNameLowLevel")
|
|
||||||
public static String getName(PlatformClass cls) {
|
public static String getName(PlatformClass cls) {
|
||||||
return cls.getMetadata().getName();
|
return cls.getMetadata().getName();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user