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();
|
||||
} else if (PlatformDetector.isWebAssemblyGC()) {
|
||||
lazyStackTrace = takeWasmGCStack();
|
||||
decorateException(this);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Import(name = "decorateException")
|
||||
private static native void decorateException(Object obj);
|
||||
|
||||
private void ensureStackTrace() {
|
||||
if (PlatformDetector.isWebAssemblyGC()) {
|
||||
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.model.WasmCustomSection;
|
||||
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.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.render.WasmBinaryRenderer;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryStatsCollector;
|
||||
|
@ -279,11 +284,46 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
|
|||
|
||||
moduleGenerator.generate();
|
||||
customGenerators.contributeToModule(module);
|
||||
generateExceptionExports(declarationsGenerator);
|
||||
adjustModuleMemory(module);
|
||||
|
||||
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(
|
||||
ClassReaderSource classes,
|
||||
WasmGCDeclarationsGenerator generator
|
||||
|
|
|
@ -147,6 +147,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
private int arrayCopyOffset = -1;
|
||||
private int cloneOffset = -1;
|
||||
private int servicesOffset = -1;
|
||||
private int throwableNativeOffset = -1;
|
||||
private WasmStructure arrayVirtualTableStruct;
|
||||
private WasmFunction arrayGetObjectFunction;
|
||||
private WasmFunction arrayLengthObjectFunction;
|
||||
|
@ -482,6 +483,11 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
return servicesOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getThrowableNativeOffset() {
|
||||
return throwableNativeOffset;
|
||||
}
|
||||
|
||||
private void initPrimitiveClass(WasmGCClassInfo classInfo, ValueType.Primitive type) {
|
||||
classInfo.initializer = target -> {
|
||||
int kind;
|
||||
|
@ -1221,6 +1227,11 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
var field = new WasmField(WasmType.Reference.EXTERN.asStorage(), "nativeRef");
|
||||
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")) {
|
||||
var cls = classSource.get("java.lang.Class");
|
||||
classFlagsOffset = fields.size();
|
||||
|
|
|
@ -73,6 +73,8 @@ public interface WasmGCClassInfoProvider {
|
|||
|
||||
int getServicesOffset();
|
||||
|
||||
int getThrowableNativeOffset();
|
||||
|
||||
default WasmGCClassInfo getClassInfo(String name) {
|
||||
return getClassInfo(ValueType.object(name));
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ class JavaError extends Error {
|
|||
super();
|
||||
this.#context = context;
|
||||
this[javaExceptionSymbol] = javaException;
|
||||
context.exports["teavm.setJsException"](javaException, this);
|
||||
}
|
||||
get message() {
|
||||
let exceptionMessage = this.#context.exports["teavm.exceptionMessage"];
|
||||
|
@ -180,6 +181,9 @@ function coreImports(imports, context) {
|
|||
return result;
|
||||
}
|
||||
};
|
||||
},
|
||||
decorateException(javaException) {
|
||||
new JavaError(context, javaException);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -195,7 +199,6 @@ function jsoImports(imports, context) {
|
|||
let primitiveWrappers = new Map();
|
||||
let primitiveFinalization = new FinalizationRegistry(token => primitiveWrappers.delete(token));
|
||||
let hashCodes = new WeakMap();
|
||||
let javaExceptionWrappers = new WeakMap();
|
||||
let lastHashCode = 2463534242;
|
||||
let nextHashCode = () => {
|
||||
let x = lastHashCode;
|
||||
|
@ -235,21 +238,17 @@ function jsoImports(imports, context) {
|
|||
function javaExceptionToJs(e) {
|
||||
if (e instanceof WebAssembly.Exception) {
|
||||
let tag = context.exports["teavm.javaException"];
|
||||
let getJsException = context.exports["teavm.getJsException"];
|
||||
if (e.is(tag)) {
|
||||
let javaException = e.getArg(tag, 0);
|
||||
let extracted = extractException(javaException);
|
||||
if (extracted !== null) {
|
||||
return extracted;
|
||||
}
|
||||
let wrapperRef = javaExceptionWrappers.get(javaException);
|
||||
if (typeof wrapperRef != "undefined") {
|
||||
let wrapper = wrapperRef.deref();
|
||||
if (typeof wrapper !== "undefined") {
|
||||
return wrapper;
|
||||
}
|
||||
let wrapper = getJsException(javaException);
|
||||
if (typeof wrapper === "undefined") {
|
||||
wrapper = new JavaError(context, javaException);
|
||||
}
|
||||
let wrapper = new JavaError(context, javaException);
|
||||
javaExceptionWrappers.set(javaException, new WeakRef(wrapper));
|
||||
return wrapper;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user