mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04:10 -08:00
wasm gc: improve exception stack trace when exception is thrown from wasm and rethrown between Java and JS
This commit is contained in:
parent
24d672e820
commit
2e0864017b
|
@ -111,10 +111,14 @@ public class TThrowable extends RuntimeException {
|
||||||
stackTrace = (TStackTraceElement[]) (Object) ExceptionHandling.fillStackTrace();
|
stackTrace = (TStackTraceElement[]) (Object) ExceptionHandling.fillStackTrace();
|
||||||
} else if (PlatformDetector.isWebAssemblyGC()) {
|
} else if (PlatformDetector.isWebAssemblyGC()) {
|
||||||
lazyStackTrace = takeWasmGCStack();
|
lazyStackTrace = takeWasmGCStack();
|
||||||
|
decorateException(this);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Import(name = "decorateException")
|
||||||
|
private static native void decorateException(Object obj);
|
||||||
|
|
||||||
private void ensureStackTrace() {
|
private void ensureStackTrace() {
|
||||||
if (PlatformDetector.isWebAssemblyGC()) {
|
if (PlatformDetector.isWebAssemblyGC()) {
|
||||||
if (lazyStackTrace != null) {
|
if (lazyStackTrace != null) {
|
||||||
|
|
|
@ -46,8 +46,13 @@ import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicFactory;
|
||||||
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsics;
|
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsics;
|
||||||
import org.teavm.backend.wasm.model.WasmCustomSection;
|
import org.teavm.backend.wasm.model.WasmCustomSection;
|
||||||
import org.teavm.backend.wasm.model.WasmFunction;
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
|
import org.teavm.backend.wasm.model.WasmLocal;
|
||||||
import org.teavm.backend.wasm.model.WasmModule;
|
import org.teavm.backend.wasm.model.WasmModule;
|
||||||
import org.teavm.backend.wasm.model.WasmTag;
|
import org.teavm.backend.wasm.model.WasmTag;
|
||||||
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||||
import org.teavm.backend.wasm.optimization.WasmUsageCounter;
|
import org.teavm.backend.wasm.optimization.WasmUsageCounter;
|
||||||
import org.teavm.backend.wasm.render.WasmBinaryRenderer;
|
import org.teavm.backend.wasm.render.WasmBinaryRenderer;
|
||||||
import org.teavm.backend.wasm.render.WasmBinaryStatsCollector;
|
import org.teavm.backend.wasm.render.WasmBinaryStatsCollector;
|
||||||
|
@ -279,11 +284,46 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
|
||||||
|
|
||||||
moduleGenerator.generate();
|
moduleGenerator.generate();
|
||||||
customGenerators.contributeToModule(module);
|
customGenerators.contributeToModule(module);
|
||||||
|
generateExceptionExports(declarationsGenerator);
|
||||||
adjustModuleMemory(module);
|
adjustModuleMemory(module);
|
||||||
|
|
||||||
emitWasmFile(module, buildTarget, outputName, debugInfoBuilder);
|
emitWasmFile(module, buildTarget, outputName, debugInfoBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generateExceptionExports(WasmGCDeclarationsGenerator declarationsGenerator) {
|
||||||
|
var nativeExceptionField = declarationsGenerator.classInfoProvider().getThrowableNativeOffset();
|
||||||
|
if (nativeExceptionField < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var throwableType = declarationsGenerator.classInfoProvider().getClassInfo("java.lang.Throwable")
|
||||||
|
.getStructure();
|
||||||
|
|
||||||
|
var getFunction = new WasmFunction(declarationsGenerator.functionTypes.of(
|
||||||
|
WasmType.Reference.EXTERN, throwableType.getReference()
|
||||||
|
));
|
||||||
|
getFunction.setName("teavm.getJsException");
|
||||||
|
getFunction.setExportName("teavm.getJsException");
|
||||||
|
var getParam = new WasmLocal(throwableType.getReference(), "javaException");
|
||||||
|
getFunction.add(getParam);
|
||||||
|
var getField = new WasmStructGet(throwableType, new WasmGetLocal(getParam), nativeExceptionField);
|
||||||
|
getFunction.getBody().add(getField);
|
||||||
|
declarationsGenerator.module.functions.add(getFunction);
|
||||||
|
|
||||||
|
var setFunction = new WasmFunction(declarationsGenerator.functionTypes.of(null, throwableType.getReference(),
|
||||||
|
WasmType.Reference.EXTERN));
|
||||||
|
setFunction.setName("teavm.setJsException");
|
||||||
|
setFunction.setExportName("teavm.setJsException");
|
||||||
|
var setParam = new WasmLocal(throwableType.getReference(), "javaException");
|
||||||
|
var setValue = new WasmLocal(WasmType.Reference.EXTERN, "jsException");
|
||||||
|
setFunction.add(setParam);
|
||||||
|
setFunction.add(setValue);
|
||||||
|
var setField = new WasmStructSet(throwableType, new WasmGetLocal(setParam),
|
||||||
|
nativeExceptionField, new WasmGetLocal(setValue));
|
||||||
|
setFunction.getBody().add(setField);
|
||||||
|
declarationsGenerator.module.functions.add(setFunction);
|
||||||
|
}
|
||||||
|
|
||||||
private WasmGCClassConsumerContext createClassConsumerContext(
|
private WasmGCClassConsumerContext createClassConsumerContext(
|
||||||
ClassReaderSource classes,
|
ClassReaderSource classes,
|
||||||
WasmGCDeclarationsGenerator generator
|
WasmGCDeclarationsGenerator generator
|
||||||
|
|
|
@ -147,6 +147,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
private int arrayCopyOffset = -1;
|
private int arrayCopyOffset = -1;
|
||||||
private int cloneOffset = -1;
|
private int cloneOffset = -1;
|
||||||
private int servicesOffset = -1;
|
private int servicesOffset = -1;
|
||||||
|
private int throwableNativeOffset = -1;
|
||||||
private WasmStructure arrayVirtualTableStruct;
|
private WasmStructure arrayVirtualTableStruct;
|
||||||
private WasmFunction arrayGetObjectFunction;
|
private WasmFunction arrayGetObjectFunction;
|
||||||
private WasmFunction arrayLengthObjectFunction;
|
private WasmFunction arrayLengthObjectFunction;
|
||||||
|
@ -482,6 +483,11 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
return servicesOffset;
|
return servicesOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getThrowableNativeOffset() {
|
||||||
|
return throwableNativeOffset;
|
||||||
|
}
|
||||||
|
|
||||||
private void initPrimitiveClass(WasmGCClassInfo classInfo, ValueType.Primitive type) {
|
private void initPrimitiveClass(WasmGCClassInfo classInfo, ValueType.Primitive type) {
|
||||||
classInfo.initializer = target -> {
|
classInfo.initializer = target -> {
|
||||||
int kind;
|
int kind;
|
||||||
|
@ -1221,6 +1227,11 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
var field = new WasmField(WasmType.Reference.EXTERN.asStorage(), "nativeRef");
|
var field = new WasmField(WasmType.Reference.EXTERN.asStorage(), "nativeRef");
|
||||||
fields.add(field);
|
fields.add(field);
|
||||||
}
|
}
|
||||||
|
if (className.equals("java.lang.Throwable")) {
|
||||||
|
throwableNativeOffset = fields.size();
|
||||||
|
var field = new WasmField(WasmType.Reference.EXTERN.asStorage(), "nativeRef");
|
||||||
|
fields.add(field);
|
||||||
|
}
|
||||||
if (className.equals("java.lang.Class")) {
|
if (className.equals("java.lang.Class")) {
|
||||||
var cls = classSource.get("java.lang.Class");
|
var cls = classSource.get("java.lang.Class");
|
||||||
classFlagsOffset = fields.size();
|
classFlagsOffset = fields.size();
|
||||||
|
|
|
@ -73,6 +73,8 @@ public interface WasmGCClassInfoProvider {
|
||||||
|
|
||||||
int getServicesOffset();
|
int getServicesOffset();
|
||||||
|
|
||||||
|
int getThrowableNativeOffset();
|
||||||
|
|
||||||
default WasmGCClassInfo getClassInfo(String name) {
|
default WasmGCClassInfo getClassInfo(String name) {
|
||||||
return getClassInfo(ValueType.object(name));
|
return getClassInfo(ValueType.object(name));
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ class JavaError extends Error {
|
||||||
super();
|
super();
|
||||||
this.#context = context;
|
this.#context = context;
|
||||||
this[javaExceptionSymbol] = javaException;
|
this[javaExceptionSymbol] = javaException;
|
||||||
|
context.exports["teavm.setJsException"](javaException, this);
|
||||||
}
|
}
|
||||||
get message() {
|
get message() {
|
||||||
let exceptionMessage = this.#context.exports["teavm.exceptionMessage"];
|
let exceptionMessage = this.#context.exports["teavm.exceptionMessage"];
|
||||||
|
@ -180,6 +181,9 @@ function coreImports(imports, context) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
decorateException(javaException) {
|
||||||
|
new JavaError(context, javaException);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -195,7 +199,6 @@ function jsoImports(imports, context) {
|
||||||
let primitiveWrappers = new Map();
|
let primitiveWrappers = new Map();
|
||||||
let primitiveFinalization = new FinalizationRegistry(token => primitiveWrappers.delete(token));
|
let primitiveFinalization = new FinalizationRegistry(token => primitiveWrappers.delete(token));
|
||||||
let hashCodes = new WeakMap();
|
let hashCodes = new WeakMap();
|
||||||
let javaExceptionWrappers = new WeakMap();
|
|
||||||
let lastHashCode = 2463534242;
|
let lastHashCode = 2463534242;
|
||||||
let nextHashCode = () => {
|
let nextHashCode = () => {
|
||||||
let x = lastHashCode;
|
let x = lastHashCode;
|
||||||
|
@ -235,21 +238,17 @@ function jsoImports(imports, context) {
|
||||||
function javaExceptionToJs(e) {
|
function javaExceptionToJs(e) {
|
||||||
if (e instanceof WebAssembly.Exception) {
|
if (e instanceof WebAssembly.Exception) {
|
||||||
let tag = context.exports["teavm.javaException"];
|
let tag = context.exports["teavm.javaException"];
|
||||||
|
let getJsException = context.exports["teavm.getJsException"];
|
||||||
if (e.is(tag)) {
|
if (e.is(tag)) {
|
||||||
let javaException = e.getArg(tag, 0);
|
let javaException = e.getArg(tag, 0);
|
||||||
let extracted = extractException(javaException);
|
let extracted = extractException(javaException);
|
||||||
if (extracted !== null) {
|
if (extracted !== null) {
|
||||||
return extracted;
|
return extracted;
|
||||||
}
|
}
|
||||||
let wrapperRef = javaExceptionWrappers.get(javaException);
|
let wrapper = getJsException(javaException);
|
||||||
if (typeof wrapperRef != "undefined") {
|
if (typeof wrapper === "undefined") {
|
||||||
let wrapper = wrapperRef.deref();
|
wrapper = new JavaError(context, javaException);
|
||||||
if (typeof wrapper !== "undefined") {
|
|
||||||
return wrapper;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let wrapper = new JavaError(context, javaException);
|
|
||||||
javaExceptionWrappers.set(javaException, new WeakRef(wrapper));
|
|
||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user