mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04:10 -08:00
wasm gc: support JS exceptions
This commit is contained in:
parent
1d47146f43
commit
3218a00eb9
|
@ -110,16 +110,17 @@ TeaVM.wasm = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function jsoImports(imports) {
|
function jsoImports(imports) {
|
||||||
|
|
||||||
let javaObjectSymbol = Symbol("javaObject");
|
let javaObjectSymbol = Symbol("javaObject");
|
||||||
let functionsSymbol = Symbol("functions");
|
let functionsSymbol = Symbol("functions");
|
||||||
let functionOriginSymbol = Symbol("functionOrigin");
|
let functionOriginSymbol = Symbol("functionOrigin");
|
||||||
|
let javaExceptionSymbol = Symbol("javaException");
|
||||||
|
|
||||||
let jsWrappers = new WeakMap();
|
let jsWrappers = new WeakMap();
|
||||||
let javaWrappers = new WeakMap();
|
let javaWrappers = new WeakMap();
|
||||||
let primitiveWrappers = new Map();
|
let primitiveWrappers = new Map();
|
||||||
let primitiveFinalization = new FinalizationRegistry(token => primitiveFinalization.delete(token));
|
let primitiveFinalization = new FinalizationRegistry(token => primitiveFinalization.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;
|
||||||
|
@ -156,6 +157,53 @@ TeaVM.wasm = function() {
|
||||||
obj[prop] = value;
|
obj[prop] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function javaExceptionToJs(e) {
|
||||||
|
if (e instanceof WebAssembly.Exception) {
|
||||||
|
let tag = exports["javaException"];
|
||||||
|
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 = new Error();
|
||||||
|
javaExceptionWrappers.set(javaException, new WeakRef(wrapper));
|
||||||
|
wrapper[javaExceptionSymbol] = javaException;
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
function jsExceptionAsJava(e) {
|
||||||
|
if (javaExceptionSymbol in e) {
|
||||||
|
return e[javaExceptionSymbol];
|
||||||
|
} else {
|
||||||
|
return exports["teavm.js.wrapException"](e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function rethrowJsAsJava(e) {
|
||||||
|
exports["teavm.js.throwException"](jsExceptionAsJava(e));
|
||||||
|
}
|
||||||
|
function extractException(e) {
|
||||||
|
return exports["teavm.js.extractException"](e);
|
||||||
|
}
|
||||||
|
function rethrowJavaAsJs(e) {
|
||||||
|
throw javaExceptionToJs(e);
|
||||||
|
}
|
||||||
|
function getProperty(obj, prop) {
|
||||||
|
try {
|
||||||
|
return obj !== null ? obj[prop] : getGlobalName(prop)
|
||||||
|
} catch (e) {
|
||||||
|
rethrowJsAsJava(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
imports.teavmJso = {
|
imports.teavmJso = {
|
||||||
emptyString: () => "",
|
emptyString: () => "",
|
||||||
stringFromCharCode: code => String.fromCharCode(code),
|
stringFromCharCode: code => String.fromCharCode(code),
|
||||||
|
@ -166,11 +214,17 @@ TeaVM.wasm = function() {
|
||||||
appendToArray: (array, e) => array.push(e),
|
appendToArray: (array, e) => array.push(e),
|
||||||
unwrapBoolean: value => value ? 1 : 0,
|
unwrapBoolean: value => value ? 1 : 0,
|
||||||
wrapBoolean: value => !!value,
|
wrapBoolean: value => !!value,
|
||||||
getProperty: (obj, prop) => obj !== null ? obj[prop] : getGlobalName(prop),
|
getProperty: getProperty,
|
||||||
getPropertyPure: (obj, prop) => obj !== null ? obj[prop] : getGlobalName(prop),
|
getPropertyPure: getProperty,
|
||||||
setProperty: setProperty,
|
setProperty: setProperty,
|
||||||
setPropertyPure: setProperty,
|
setPropertyPure: setProperty,
|
||||||
global: getGlobalName,
|
global(name) {
|
||||||
|
try {
|
||||||
|
return getGlobalName(name);
|
||||||
|
} catch (e) {
|
||||||
|
rethrowJsAsJava(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
createClass(name) {
|
createClass(name) {
|
||||||
let fn = new Function(
|
let fn = new Function(
|
||||||
"javaObjectSymbol",
|
"javaObjectSymbol",
|
||||||
|
@ -184,18 +238,30 @@ TeaVM.wasm = function() {
|
||||||
},
|
},
|
||||||
defineMethod(cls, name, fn) {
|
defineMethod(cls, name, fn) {
|
||||||
cls.prototype[name] = function(...args) {
|
cls.prototype[name] = function(...args) {
|
||||||
return fn(this, ...args);
|
try {
|
||||||
|
return fn(this, ...args);
|
||||||
|
} catch (e) {
|
||||||
|
rethrowJavaAsJs(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
defineProperty(cls, name, getFn, setFn) {
|
defineProperty(cls, name, getFn, setFn) {
|
||||||
let descriptor = {
|
let descriptor = {
|
||||||
get() {
|
get() {
|
||||||
return getFn(this);
|
try {
|
||||||
|
return getFn(this);
|
||||||
|
} catch (e) {
|
||||||
|
rethrowJavaAsJs(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (setFn !== null) {
|
if (setFn !== null) {
|
||||||
descriptor.set = function(value) {
|
descriptor.set = function(value) {
|
||||||
setFn(this, value);
|
try {
|
||||||
|
setFn(this, value);
|
||||||
|
} catch (e) {
|
||||||
|
rethrowJavaAsJs(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Object.defineProperty(cls.prototype, name, descriptor);
|
Object.defineProperty(cls.prototype, name, descriptor);
|
||||||
|
@ -239,7 +305,15 @@ TeaVM.wasm = function() {
|
||||||
return origin;
|
return origin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { [property]: fn };
|
return {
|
||||||
|
[property]: function(...args) {
|
||||||
|
try {
|
||||||
|
return fn(...args);
|
||||||
|
} catch (e) {
|
||||||
|
rethrowJavaAsJs(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
},
|
},
|
||||||
wrapObject(obj) {
|
wrapObject(obj) {
|
||||||
if (obj === null) {
|
if (obj === null) {
|
||||||
|
@ -298,25 +372,47 @@ TeaVM.wasm = function() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
apply: (instance, method, args) => {
|
apply: (instance, method, args) => {
|
||||||
if (instance === null) {
|
try {
|
||||||
let fn = getGlobalName(method);
|
if (instance === null) {
|
||||||
return fn(...args);
|
let fn = getGlobalName(method);
|
||||||
} else {
|
return fn(...args);
|
||||||
return instance[method](...args);
|
} else {
|
||||||
|
return instance[method](...args);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
rethrowJsAsJava(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
concatArray: (a, b) => a.concat(b)
|
concatArray: (a, b) => a.concat(b),
|
||||||
|
getJavaException: e => e[javaExceptionSymbol]
|
||||||
};
|
};
|
||||||
for (let name of ["wrapByte", "wrapShort", "wrapChar", "wrapInt", "wrapFloat", "wrapDouble", "unwrapByte",
|
for (let name of ["wrapByte", "wrapShort", "wrapChar", "wrapInt", "wrapFloat", "wrapDouble", "unwrapByte",
|
||||||
"unwrapShort", "unwrapChar", "unwrapInt", "unwrapFloat", "unwrapDouble"]) {
|
"unwrapShort", "unwrapChar", "unwrapInt", "unwrapFloat", "unwrapDouble"]) {
|
||||||
imports.teavmJso[name] = identity;
|
imports.teavmJso[name] = identity;
|
||||||
}
|
}
|
||||||
for (let i = 0; i < 32; ++i) {
|
for (let i = 0; i < 32; ++i) {
|
||||||
imports.teavmJso["createFunction" + i] = (...args) => new Function(...args);
|
imports.teavmJso["createFunction" + i] = (...args) => new Function(...args);
|
||||||
imports.teavmJso["callFunction" + i] = (fn, ...args) => fn(...args);
|
imports.teavmJso["callFunction" + i] = (fn, ...args) => {
|
||||||
imports.teavmJso["callMethod" + i] = (instance, method, ...args) =>
|
try {
|
||||||
instance !== null ? instance[method](...args) : getGlobalName(method)(...args);
|
return fn(...args);
|
||||||
imports.teavmJso["construct" + i] = (constructor, ...args) => new constructor(...args);
|
} catch (e) {
|
||||||
|
rethrowJsAsJava(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
imports.teavmJso["callMethod" + i] = (instance, method, ...args) => {
|
||||||
|
try {
|
||||||
|
return instance !== null ? instance[method](...args) : getGlobalName(method)(...args);
|
||||||
|
} catch (e) {
|
||||||
|
rethrowJsAsJava(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
imports.teavmJso["construct" + i] = (constructor, ...args) => {
|
||||||
|
try {
|
||||||
|
return new constructor(...args);
|
||||||
|
} catch (e) {
|
||||||
|
rethrowJsAsJava(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
imports.teavmJso["arrayOf" + i] = (...args) => args
|
imports.teavmJso["arrayOf" + i] = (...args) => args
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ configurations {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
"teavm"(project(":jso:impl"))
|
"teavm"(project(":jso:impl"))
|
||||||
|
compileOnly(project(":interop:core"))
|
||||||
}
|
}
|
||||||
|
|
||||||
teavmPublish {
|
teavmPublish {
|
||||||
|
|
|
@ -15,10 +15,13 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.jso;
|
package org.teavm.jso;
|
||||||
|
|
||||||
|
import org.teavm.interop.Import;
|
||||||
|
|
||||||
public final class JSExceptions {
|
public final class JSExceptions {
|
||||||
private JSExceptions() {
|
private JSExceptions() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Import(name = "getJavaException", module = "teavmJso")
|
||||||
public static native Throwable getJavaException(JSObject e);
|
public static native Throwable getJavaException(JSObject e);
|
||||||
|
|
||||||
public static native JSObject getJSException(Throwable e);
|
public static native JSObject getJSException(Throwable e);
|
||||||
|
|
|
@ -68,7 +68,7 @@ class JSValueMarshaller {
|
||||||
String className = ((ValueType.Object) type).getClassName();
|
String className = ((ValueType.Object) type).getClassName();
|
||||||
ClassReader cls = classSource.get(className);
|
ClassReader cls = classSource.get(className);
|
||||||
if (cls != null && cls.getAnnotations().get(JSFunctor.class.getName()) != null) {
|
if (cls != null && cls.getAnnotations().get(JSFunctor.class.getName()) != null) {
|
||||||
return wrapFunctor(location, var, cls);
|
return wrapFunctor(location, var, cls, jsType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return wrap(var, type, jsType, location.getSourceLocation(), byRef);
|
return wrap(var, type, jsType, location.getSourceLocation(), byRef);
|
||||||
|
@ -83,20 +83,22 @@ class JSValueMarshaller {
|
||||||
.count() == 1;
|
.count() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Variable wrapFunctor(CallLocation location, Variable var, ClassReader type) {
|
private Variable wrapFunctor(CallLocation location, Variable var, ClassReader type, JSType jsType) {
|
||||||
if (!isProperFunctor(type)) {
|
if (!isProperFunctor(type)) {
|
||||||
diagnostics.error(location, "Wrong functor: {{c0}}", type.getName());
|
diagnostics.error(location, "Wrong functor: {{c0}}", type.getName());
|
||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
|
||||||
var unwrapNative = new InvokeInstruction();
|
if (jsType == JSType.JAVA) {
|
||||||
unwrapNative.setLocation(location.getSourceLocation());
|
var unwrapNative = new InvokeInstruction();
|
||||||
unwrapNative.setType(InvocationType.SPECIAL);
|
unwrapNative.setLocation(location.getSourceLocation());
|
||||||
unwrapNative.setMethod(JSMethods.UNWRAP);
|
unwrapNative.setType(InvocationType.SPECIAL);
|
||||||
unwrapNative.setArguments(var);
|
unwrapNative.setMethod(JSMethods.UNWRAP);
|
||||||
unwrapNative.setReceiver(program.createVariable());
|
unwrapNative.setArguments(var);
|
||||||
replacement.add(unwrapNative);
|
unwrapNative.setReceiver(program.createVariable());
|
||||||
var = unwrapNative.getReceiver();
|
replacement.add(unwrapNative);
|
||||||
|
var = unwrapNative.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
String name = type.getMethods().stream()
|
String name = type.getMethods().stream()
|
||||||
.filter(method -> method.hasModifier(ElementModifier.ABSTRACT))
|
.filter(method -> method.hasModifier(ElementModifier.ABSTRACT))
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 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.jso.impl.wasmgc;
|
||||||
|
|
||||||
|
import org.teavm.jso.JSObject;
|
||||||
|
import org.teavm.jso.core.JSError;
|
||||||
|
|
||||||
|
class WasmGCExceptionWrapper extends RuntimeException {
|
||||||
|
final JSObject jsException;
|
||||||
|
|
||||||
|
WasmGCExceptionWrapper(JSObject jsException) {
|
||||||
|
this.jsException = jsException;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
var message = jsException instanceof JSError
|
||||||
|
? ((JSError) jsException).getMessage()
|
||||||
|
: jsException.toString();
|
||||||
|
return "(JavaScript) Error: " + message;
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,16 +28,7 @@ import org.teavm.model.MethodReference;
|
||||||
class WasmGCJSDependencies extends AbstractDependencyListener {
|
class WasmGCJSDependencies extends AbstractDependencyListener {
|
||||||
@Override
|
@Override
|
||||||
public void started(DependencyAgent agent) {
|
public void started(DependencyAgent agent) {
|
||||||
agent.linkMethod(STRING_TO_JS)
|
reachUtilities(agent);
|
||||||
.propagate(1, agent.getType("java.lang.String"))
|
|
||||||
.use();
|
|
||||||
|
|
||||||
var jsToString = agent.linkMethod(JS_TO_STRING);
|
|
||||||
jsToString.getResult().propagate(agent.getType("java.lang.String"));
|
|
||||||
jsToString.use();
|
|
||||||
|
|
||||||
agent.linkMethod(new MethodReference(JSWrapper.class, "createWrapper", JSObject.class, Object.class))
|
|
||||||
.use();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -46,6 +37,26 @@ class WasmGCJSDependencies extends AbstractDependencyListener {
|
||||||
if (method.getMethod().getName().equals("jsArrayItem")) {
|
if (method.getMethod().getName().equals("jsArrayItem")) {
|
||||||
method.getVariable(1).getArrayItem().connect(method.getResult());
|
method.getVariable(1).getArrayItem().connect(method.getResult());
|
||||||
}
|
}
|
||||||
|
} else if (method.getMethod().getOwnerName().equals(JSWrapper.class.getName())) {
|
||||||
|
if (method.getMethod().getName().equals("wrap")) {
|
||||||
|
agent.linkMethod(new MethodReference(JSWrapper.class, "createWrapper", JSObject.class, Object.class))
|
||||||
|
.use();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void reachUtilities(DependencyAgent agent) {
|
||||||
|
agent.linkMethod(STRING_TO_JS)
|
||||||
|
.propagate(1, agent.getType("java.lang.String"))
|
||||||
|
.use();
|
||||||
|
|
||||||
|
var jsToString = agent.linkMethod(JS_TO_STRING);
|
||||||
|
jsToString.getResult().propagate(agent.getType("java.lang.String"));
|
||||||
|
jsToString.use();
|
||||||
|
|
||||||
|
agent.linkMethod(new MethodReference(WasmGCJSRuntime.class, "wrapException", JSObject.class, Throwable.class))
|
||||||
|
.use();
|
||||||
|
agent.linkMethod(new MethodReference(WasmGCJSRuntime.class, "extractException", Throwable.class,
|
||||||
|
JSObject.class)).use();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,4 +65,12 @@ final class WasmGCJSRuntime {
|
||||||
|
|
||||||
@Import(name = "charAt", module = "teavmJso")
|
@Import(name = "charAt", module = "teavmJso")
|
||||||
static native char charAt(JSObject str, int index);
|
static native char charAt(JSObject str, int index);
|
||||||
|
|
||||||
|
static Throwable wrapException(JSObject obj) {
|
||||||
|
return new WasmGCExceptionWrapper(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSObject extractException(Throwable e) {
|
||||||
|
return e instanceof WasmGCExceptionWrapper ? ((WasmGCExceptionWrapper) e).jsException : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,20 +22,30 @@ import java.util.function.Consumer;
|
||||||
import org.teavm.backend.javascript.rendering.AstWriter;
|
import org.teavm.backend.javascript.rendering.AstWriter;
|
||||||
import org.teavm.backend.wasm.model.WasmFunction;
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
import org.teavm.backend.wasm.model.WasmGlobal;
|
import org.teavm.backend.wasm.model.WasmGlobal;
|
||||||
|
import org.teavm.backend.wasm.model.WasmLocal;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmCast;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmExternConversion;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmExternConversionType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
|
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmNullConstant;
|
import org.teavm.backend.wasm.model.expression.WasmNullConstant;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
|
import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmThrow;
|
||||||
|
import org.teavm.jso.JSObject;
|
||||||
import org.teavm.jso.impl.JSBodyAstEmitter;
|
import org.teavm.jso.impl.JSBodyAstEmitter;
|
||||||
import org.teavm.jso.impl.JSBodyBloatedEmitter;
|
import org.teavm.jso.impl.JSBodyBloatedEmitter;
|
||||||
import org.teavm.jso.impl.JSBodyEmitter;
|
import org.teavm.jso.impl.JSBodyEmitter;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
|
||||||
class WasmGCJsoCommonGenerator {
|
class WasmGCJsoCommonGenerator {
|
||||||
private WasmGCJSFunctions jsFunctions;
|
private WasmGCJSFunctions jsFunctions;
|
||||||
private boolean initialized;
|
private boolean initialized;
|
||||||
private List<Consumer<WasmFunction>> initializerParts = new ArrayList<>();
|
private List<Consumer<WasmFunction>> initializerParts = new ArrayList<>();
|
||||||
|
private boolean rethrowExported;
|
||||||
|
|
||||||
WasmGCJsoCommonGenerator(WasmGCJSFunctions jsFunctions) {
|
WasmGCJsoCommonGenerator(WasmGCJSFunctions jsFunctions) {
|
||||||
this.jsFunctions = jsFunctions;
|
this.jsFunctions = jsFunctions;
|
||||||
|
@ -47,6 +57,7 @@ class WasmGCJsoCommonGenerator {
|
||||||
}
|
}
|
||||||
initialized = true;
|
initialized = true;
|
||||||
context.addToInitializer(this::writeToInitializer);
|
context.addToInitializer(this::writeToInitializer);
|
||||||
|
exportRethrowException(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeToInitializer(WasmFunction function) {
|
private void writeToInitializer(WasmFunction function) {
|
||||||
|
@ -55,7 +66,8 @@ class WasmGCJsoCommonGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addInitializerPart(Consumer<WasmFunction> part) {
|
void addInitializerPart(WasmGCJsoContext context, Consumer<WasmFunction> part) {
|
||||||
|
initialize(context);
|
||||||
initializerParts.add(part);
|
initializerParts.add(part);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,4 +126,37 @@ class WasmGCJsoCommonGenerator {
|
||||||
WasmExpression stringToJs(WasmGCJsoContext context, WasmExpression str) {
|
WasmExpression stringToJs(WasmGCJsoContext context, WasmExpression str) {
|
||||||
return new WasmCall(stringToJsFunction(context), str);
|
return new WasmCall(stringToJsFunction(context), str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void exportRethrowException(WasmGCJsoContext context) {
|
||||||
|
if (rethrowExported) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rethrowExported = true;
|
||||||
|
var fn = context.functions().forStaticMethod(new MethodReference(WasmGCJSRuntime.class, "wrapException",
|
||||||
|
JSObject.class, Throwable.class));
|
||||||
|
fn.setExportName("teavm.js.wrapException");
|
||||||
|
|
||||||
|
fn = context.functions().forStaticMethod(new MethodReference(WasmGCJSRuntime.class, "extractException",
|
||||||
|
Throwable.class, JSObject.class));
|
||||||
|
fn.setExportName("teavm.js.extractException");
|
||||||
|
|
||||||
|
createThrowExceptionFunction(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createThrowExceptionFunction(WasmGCJsoContext context) {
|
||||||
|
var fn = new WasmFunction(context.functionTypes().of(null, WasmType.Reference.EXTERN));
|
||||||
|
fn.setName(context.names().topLevel("teavm@throwException"));
|
||||||
|
fn.setExportName("teavm.js.throwException");
|
||||||
|
context.module().functions.add(fn);
|
||||||
|
|
||||||
|
var exceptionLocal = new WasmLocal(WasmType.Reference.EXTERN);
|
||||||
|
fn.add(exceptionLocal);
|
||||||
|
|
||||||
|
var asAny = new WasmExternConversion(WasmExternConversionType.EXTERN_TO_ANY, new WasmGetLocal(exceptionLocal));
|
||||||
|
var throwableType = (WasmType.Reference) context.typeMapper().mapType(ValueType.parse(Throwable.class));
|
||||||
|
var asThrowable = new WasmCast(asAny, throwableType);
|
||||||
|
var throwExpr = new WasmThrow(context.exceptionTag());
|
||||||
|
throwExpr.getArguments().add(asThrowable);
|
||||||
|
fn.getBody().add(throwExpr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,11 +19,13 @@ import java.util.function.Consumer;
|
||||||
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
||||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||||
import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider;
|
import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider;
|
||||||
|
import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper;
|
||||||
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringProvider;
|
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringProvider;
|
||||||
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGeneratorContext;
|
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGeneratorContext;
|
||||||
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicContext;
|
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicContext;
|
||||||
import org.teavm.backend.wasm.model.WasmFunction;
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
import org.teavm.backend.wasm.model.WasmModule;
|
import org.teavm.backend.wasm.model.WasmModule;
|
||||||
|
import org.teavm.backend.wasm.model.WasmTag;
|
||||||
|
|
||||||
interface WasmGCJsoContext {
|
interface WasmGCJsoContext {
|
||||||
WasmModule module();
|
WasmModule module();
|
||||||
|
@ -36,6 +38,10 @@ interface WasmGCJsoContext {
|
||||||
|
|
||||||
WasmGCStringProvider strings();
|
WasmGCStringProvider strings();
|
||||||
|
|
||||||
|
WasmGCTypeMapper typeMapper();
|
||||||
|
|
||||||
|
WasmTag exceptionTag();
|
||||||
|
|
||||||
void addToInitializer(Consumer<WasmFunction> initializerContributor);
|
void addToInitializer(Consumer<WasmFunction> initializerContributor);
|
||||||
|
|
||||||
static WasmGCJsoContext wrap(WasmGCIntrinsicContext context) {
|
static WasmGCJsoContext wrap(WasmGCIntrinsicContext context) {
|
||||||
|
@ -65,6 +71,16 @@ interface WasmGCJsoContext {
|
||||||
return context.strings();
|
return context.strings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmGCTypeMapper typeMapper() {
|
||||||
|
return context.typeMapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmTag exceptionTag() {
|
||||||
|
return context.exceptionTag();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addToInitializer(Consumer<WasmFunction> initializerContributor) {
|
public void addToInitializer(Consumer<WasmFunction> initializerContributor) {
|
||||||
context.addToInitializer(initializerContributor);
|
context.addToInitializer(initializerContributor);
|
||||||
|
@ -99,6 +115,16 @@ interface WasmGCJsoContext {
|
||||||
return context.strings();
|
return context.strings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmGCTypeMapper typeMapper() {
|
||||||
|
return context.typeMapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmTag exceptionTag() {
|
||||||
|
return context.exceptionTag();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addToInitializer(Consumer<WasmFunction> initializerContributor) {
|
public void addToInitializer(Consumer<WasmFunction> initializerContributor) {
|
||||||
context.addToInitializer(initializerContributor);
|
context.addToInitializer(initializerContributor);
|
||||||
|
|
|
@ -27,12 +27,13 @@ import org.teavm.jso.core.JSError;
|
||||||
import org.teavm.junit.EachTestCompiledSeparately;
|
import org.teavm.junit.EachTestCompiledSeparately;
|
||||||
import org.teavm.junit.OnlyPlatform;
|
import org.teavm.junit.OnlyPlatform;
|
||||||
import org.teavm.junit.SkipJVM;
|
import org.teavm.junit.SkipJVM;
|
||||||
|
import org.teavm.junit.SkipPlatform;
|
||||||
import org.teavm.junit.TeaVMTestRunner;
|
import org.teavm.junit.TeaVMTestRunner;
|
||||||
import org.teavm.junit.TestPlatform;
|
import org.teavm.junit.TestPlatform;
|
||||||
|
|
||||||
@RunWith(TeaVMTestRunner.class)
|
@RunWith(TeaVMTestRunner.class)
|
||||||
@SkipJVM
|
@SkipJVM
|
||||||
@OnlyPlatform(TestPlatform.JAVASCRIPT)
|
@OnlyPlatform({TestPlatform.JAVASCRIPT, TestPlatform.WEBASSEMBLY_GC})
|
||||||
@EachTestCompiledSeparately
|
@EachTestCompiledSeparately
|
||||||
public class ExceptionsTest {
|
public class ExceptionsTest {
|
||||||
@Test
|
@Test
|
||||||
|
@ -102,6 +103,7 @@ public class ExceptionsTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@SkipPlatform(TestPlatform.WEBASSEMBLY_GC)
|
||||||
public void catchNativeExceptionAsRuntimeException() {
|
public void catchNativeExceptionAsRuntimeException() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user