mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
wasm gc: fix exporting classes to JS
This commit is contained in:
parent
f61d893b6d
commit
14a4a99fa5
|
@ -263,15 +263,23 @@ TeaVM.wasmGC = TeaVM.wasmGC || function() {
|
||||||
params.push("p" + i);
|
params.push("p" + i);
|
||||||
}
|
}
|
||||||
let paramsAsString = params.length === 0 ? "" : params.join(", ");
|
let paramsAsString = params.length === 0 ? "" : params.join(", ");
|
||||||
return new Function("rethrowJavaAsJs", "fn", `
|
return new Function("rethrowJavaAsJs", "fn",
|
||||||
return function(${paramsAsString}) {
|
`return function(${paramsAsString}) {\n` +
|
||||||
try {
|
` try {\n` +
|
||||||
return fn(${paramsAsString});
|
` return fn(${paramsAsString});\n` +
|
||||||
} catch (e) {
|
` } catch (e) {\n` +
|
||||||
rethrowJavaAsJs(e);
|
` rethrowJavaAsJs(e);\n` +
|
||||||
|
` }\n` +
|
||||||
|
`};`
|
||||||
|
)(rethrowJavaAsJs, fn);
|
||||||
}
|
}
|
||||||
};
|
function renameConstructor(name, c) {
|
||||||
`)(rethrowJavaAsJs, fn);
|
return new Function(
|
||||||
|
"constructor",
|
||||||
|
`return function ${name}(marker, javaObject) {\n` +
|
||||||
|
` return constructor.call(this, marker, javaObject);\n` +
|
||||||
|
`}\n`
|
||||||
|
)(c);
|
||||||
}
|
}
|
||||||
imports.teavmJso = {
|
imports.teavmJso = {
|
||||||
emptyString: () => "",
|
emptyString: () => "",
|
||||||
|
@ -295,64 +303,41 @@ TeaVM.wasmGC = TeaVM.wasmGC || function() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
createClass(name, parent, constructor) {
|
createClass(name, parent, constructor) {
|
||||||
name = sanitizeName(name);
|
name = sanitizeName(name || "JavaObject");
|
||||||
|
let action;
|
||||||
if (parent === null) {
|
if (parent === null) {
|
||||||
let fn = new Function(
|
action = function (javaObject) {
|
||||||
"javaObjectSymbol",
|
|
||||||
"functionsSymbol",
|
|
||||||
"wrapperCallMarker",
|
|
||||||
"constructor",
|
|
||||||
"rethrowJavaAsJs",
|
|
||||||
`let fn;
|
|
||||||
fn = function ${name}(marker, javaObject) {
|
|
||||||
if (marker === wrapperCallMarker) {
|
|
||||||
this[javaObjectSymbol] = javaObject;
|
this[javaObjectSymbol] = javaObject;
|
||||||
this[functionsSymbol] = null;
|
this[functionsSymbol] = null;
|
||||||
} else if (constructor === null) {
|
|
||||||
throw new Error("This class can't be instantiated directly");
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
return fn(wrapperCallMarker, constructor(arguments));
|
|
||||||
} catch (e) {
|
|
||||||
rethrowJavaAsJs(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let boundFn = function(javaObject) { return fn.call(this, wrapperCallMarker, javaObject); };
|
|
||||||
boundFn[wrapperCallMarker] = fn;
|
|
||||||
boundFn.prototype = fn.prototype;
|
|
||||||
return boundFn;`
|
|
||||||
);
|
|
||||||
return fn(javaObjectSymbol, functionsSymbol, wrapperCallMarkerSymbol, constructor, rethrowJavaAsJs);
|
|
||||||
} else {
|
} else {
|
||||||
let fn = new Function(
|
action = function (javaObject) {
|
||||||
"parent",
|
|
||||||
"wrapperCallMarker",
|
|
||||||
"constructor",
|
|
||||||
"rethrowJavaAsJs",
|
|
||||||
`let fn
|
|
||||||
fn = function ${name}(marker, javaObject) {
|
|
||||||
if (marker === wrapperCallMarker) {
|
|
||||||
parent.call(this, javaObject);
|
parent.call(this, javaObject);
|
||||||
} else if (constructor === null) {
|
|
||||||
throw new Error("This class can't be instantiated directly");
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
return fn(wrapperCallMarker, constructor(arguments));
|
|
||||||
} catch (e) {
|
|
||||||
rethrowJavaAsJs(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
fn.prototype = Object.create(parent);
|
fn.prototype = Object.create(parent);
|
||||||
fn.prototype.constructor = parent;
|
fn.prototype.constructor = parent;
|
||||||
let boundFn = function(javaObject) { return fn.call(this, wrapperCallMarker, javaObject); };
|
|
||||||
boundFn[wrapperCallMarker] = fn;
|
|
||||||
boundFn.prototype = fn.prototype;
|
|
||||||
return fn;`
|
|
||||||
);
|
|
||||||
return fn(parent, wrapperCallMarkerSymbol, constructor, rethrowJavaAsJs);
|
|
||||||
}
|
}
|
||||||
|
let fn = renameConstructor(name, function (marker, javaObject) {
|
||||||
|
if (marker === wrapperCallMarkerSymbol) {
|
||||||
|
action.call(this, javaObject);
|
||||||
|
} else if (constructor === null) {
|
||||||
|
throw new Error("This class can't be instantiated directly");
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
return constructor.apply(null, arguments);
|
||||||
|
} catch (e) {
|
||||||
|
rethrowJavaAsJs(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fn.prototype = Object.create(parent || Object.prototype);
|
||||||
|
fn.prototype.constructor = fn;
|
||||||
|
let boundFn = renameConstructor(name, function(javaObject) {
|
||||||
|
return fn.call(this, wrapperCallMarkerSymbol, javaObject);
|
||||||
|
});
|
||||||
|
boundFn[wrapperCallMarkerSymbol] = fn;
|
||||||
|
boundFn.prototype = fn.prototype;
|
||||||
|
return boundFn;
|
||||||
},
|
},
|
||||||
exportClass(cls) {
|
exportClass(cls) {
|
||||||
return cls[wrapperCallMarkerSymbol];
|
return cls[wrapperCallMarkerSymbol];
|
||||||
|
@ -363,15 +348,15 @@ TeaVM.wasmGC = TeaVM.wasmGC || function() {
|
||||||
params.push("p" + i);
|
params.push("p" + i);
|
||||||
}
|
}
|
||||||
let paramsAsString = params.length === 0 ? "" : params.join(", ");
|
let paramsAsString = params.length === 0 ? "" : params.join(", ");
|
||||||
cls.prototype[name] = new Function("rethrowJavaAsJs", "fn", `
|
cls.prototype[name] = new Function("rethrowJavaAsJs", "fn",
|
||||||
return function(${paramsAsString}) {
|
`return function(${paramsAsString}) {\n` +
|
||||||
try {
|
` try {\n` +
|
||||||
return fn(${['this', params].join(", ")});
|
` return fn(${['this', params].join(", ")});\n` +
|
||||||
} catch (e) {
|
` } catch (e) {\n` +
|
||||||
rethrowJavaAsJs(e);
|
` rethrowJavaAsJs(e);\n` +
|
||||||
}
|
` }\n` +
|
||||||
};
|
`};`
|
||||||
`)(rethrowJavaAsJs, fn);
|
)(rethrowJavaAsJs, fn);
|
||||||
},
|
},
|
||||||
defineStaticMethod(cls, name, fn) {
|
defineStaticMethod(cls, name, fn) {
|
||||||
cls[name] = defineFunction(fn);
|
cls[name] = defineFunction(fn);
|
||||||
|
@ -554,32 +539,33 @@ TeaVM.wasmGC = TeaVM.wasmGC || function() {
|
||||||
for (let i = 0; i < 32; ++i) {
|
for (let i = 0; i < 32; ++i) {
|
||||||
let args = argumentList.length === 0 ? "" : argumentList.join(", ");
|
let args = argumentList.length === 0 ? "" : argumentList.join(", ");
|
||||||
let argsAndBody = [...argumentList, "body"].join(", ");
|
let argsAndBody = [...argumentList, "body"].join(", ");
|
||||||
imports.teavmJso["createFunction" + i] = new Function("wrapCallFromJavaToJs", ...argumentList, "body", `
|
imports.teavmJso["createFunction" + i] = new Function("wrapCallFromJavaToJs", ...argumentList, "body",
|
||||||
return new Function('wrapCallFromJavaToJs', ${argsAndBody}).bind(this, wrapCallFromJavaToJs);
|
`return new Function('wrapCallFromJavaToJs', ${argsAndBody}).bind(this, wrapCallFromJavaToJs);`
|
||||||
`).bind(null, wrapCallFromJavaToJs);
|
).bind(null, wrapCallFromJavaToJs);
|
||||||
imports.teavmJso["callFunction" + i] = new Function("rethrowJsAsJava", "fn", ...argumentList, `
|
imports.teavmJso["callFunction" + i] = new Function("rethrowJsAsJava", "fn", ...argumentList,
|
||||||
try {
|
`try {\n` +
|
||||||
return fn(${args});
|
` return fn(${args});\n` +
|
||||||
} catch (e) {
|
`} catch (e) {\n` +
|
||||||
rethrowJsAsJava(e);
|
` rethrowJsAsJava(e);\n` +
|
||||||
}
|
`}`
|
||||||
`).bind(null, rethrowJsAsJava);
|
).bind(null, rethrowJsAsJava);
|
||||||
imports.teavmJso["callMethod" + i] = new Function("rethrowJsAsJava", "getGlobalName", "instance",
|
imports.teavmJso["callMethod" + i] = new Function("rethrowJsAsJava", "getGlobalName", "instance",
|
||||||
"method", ...argumentList, `
|
"method", ...argumentList,
|
||||||
try {
|
`try {\n`+
|
||||||
return instance !== null
|
` return instance !== null\n` +
|
||||||
? instance[method](${args})
|
` ? instance[method](${args})\n` +
|
||||||
: getGlobalName(method)(${args});
|
` : getGlobalName(method)(${args});\n` +
|
||||||
} catch (e) {
|
`} catch (e) {\n` +
|
||||||
rethrowJsAsJava(e);
|
` rethrowJsAsJava(e);\n` +
|
||||||
}`).bind(null, rethrowJsAsJava, getGlobalName);
|
`}`
|
||||||
imports.teavmJso["construct" + i] = new Function("rethrowJsAsJava", "constructor", ...argumentList, `
|
).bind(null, rethrowJsAsJava, getGlobalName);
|
||||||
try {
|
imports.teavmJso["construct" + i] = new Function("rethrowJsAsJava", "constructor", ...argumentList,
|
||||||
return new constructor(${args});
|
`try {\n` +
|
||||||
} catch (e) {
|
` return new constructor(${args});\n` +
|
||||||
rethrowJsAsJava(e);
|
`} catch (e) {\n` +
|
||||||
}
|
` rethrowJsAsJava(e);\n` +
|
||||||
`).bind(null, rethrowJsAsJava);
|
`}`
|
||||||
|
).bind(null, rethrowJsAsJava);
|
||||||
imports.teavmJso["arrayOf" + i] = new Function(...argumentList, "return [" + args + "]");
|
imports.teavmJso["arrayOf" + i] = new Function(...argumentList, "return [" + args + "]");
|
||||||
|
|
||||||
let param = "p" + (i + 1);
|
let param = "p" + (i + 1);
|
||||||
|
|
|
@ -139,12 +139,9 @@ class JSObjectClassTransformer implements ClassHolderTransformer {
|
||||||
createWrapperMethod.setLevel(AccessLevel.PUBLIC);
|
createWrapperMethod.setLevel(AccessLevel.PUBLIC);
|
||||||
createWrapperMethod.getModifiers().add(ElementModifier.NATIVE);
|
createWrapperMethod.getModifiers().add(ElementModifier.NATIVE);
|
||||||
cls.addMethod(createWrapperMethod);
|
cls.addMethod(createWrapperMethod);
|
||||||
|
|
||||||
if (!isJavaScriptClass(cls)) {
|
|
||||||
cls.getInterfaces().add(JSMethods.JS_MARSHALLABLE);
|
cls.getInterfaces().add(JSMethods.JS_MARSHALLABLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void exposeMethods(ClassHolder classHolder, ExposedClass classToExpose, Diagnostics diagnostics,
|
private void exposeMethods(ClassHolder classHolder, ExposedClass classToExpose, Diagnostics diagnostics,
|
||||||
MethodReference functorMethod) {
|
MethodReference functorMethod) {
|
||||||
|
|
|
@ -66,6 +66,8 @@ 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 native JSObject wrapObject(Object obj);
|
||||||
|
|
||||||
static Throwable wrapException(JSObject obj) {
|
static Throwable wrapException(JSObject obj) {
|
||||||
return new WasmGCExceptionWrapper(obj);
|
return new WasmGCExceptionWrapper(obj);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 konsoletyper.
|
||||||
|
*
|
||||||
|
* 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.ast.InvocationExpr;
|
||||||
|
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic;
|
||||||
|
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicContext;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
|
||||||
|
|
||||||
|
class WasmGCJSRuntimeIntrinsic implements WasmGCIntrinsic {
|
||||||
|
private WasmGCJsoCommonGenerator commonGen;
|
||||||
|
|
||||||
|
WasmGCJSRuntimeIntrinsic(WasmGCJsoCommonGenerator commonGen) {
|
||||||
|
this.commonGen = commonGen;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) {
|
||||||
|
var jsoContext = WasmGCJsoContext.wrap(context);
|
||||||
|
var wrapperClass = commonGen.getDefaultWrapperClass(jsoContext);
|
||||||
|
var wrapperFunction = commonGen.javaObjectToJSFunction(jsoContext);
|
||||||
|
return new WasmCall(wrapperFunction, context.generate(invocation.getArguments().get(0)),
|
||||||
|
new WasmGetGlobal(wrapperClass));
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,7 +21,6 @@ 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.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.WasmExternConversion;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmExternConversionType;
|
import org.teavm.backend.wasm.model.expression.WasmExternConversionType;
|
||||||
|
@ -41,17 +40,6 @@ class WasmGCJSWrapperIntrinsic implements WasmGCIntrinsic {
|
||||||
var function = getWrapFunction(context);
|
var function = getWrapFunction(context);
|
||||||
return new WasmCall(function, context.generate(invocation.getArguments().get(0)));
|
return new WasmCall(function, context.generate(invocation.getArguments().get(0)));
|
||||||
}
|
}
|
||||||
case "dependencyJavaToJs":
|
|
||||||
case "directJavaToJs":
|
|
||||||
return new WasmExternConversion(WasmExternConversionType.ANY_TO_EXTERN,
|
|
||||||
context.generate(invocation.getArguments().get(0)));
|
|
||||||
case "dependencyJsToJava":
|
|
||||||
case "directJsToJava": {
|
|
||||||
var any = new WasmExternConversion(WasmExternConversionType.EXTERN_TO_ANY,
|
|
||||||
context.generate(invocation.getArguments().get(0)));
|
|
||||||
var objectType = context.typeMapper().mapType(ValueType.parse(Object.class));
|
|
||||||
return new WasmCast(any, (WasmType.Reference) objectType);
|
|
||||||
}
|
|
||||||
case "isJava": {
|
case "isJava": {
|
||||||
var convert = new WasmExternConversion(WasmExternConversionType.EXTERN_TO_ANY,
|
var convert = new WasmExternConversion(WasmExternConversionType.EXTERN_TO_ANY,
|
||||||
context.generate(invocation.getArguments().get(0)));
|
context.generate(invocation.getArguments().get(0)));
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.teavm.model.ClassHolderTransformerContext;
|
||||||
import org.teavm.model.ElementModifier;
|
import org.teavm.model.ElementModifier;
|
||||||
import org.teavm.model.MethodDescriptor;
|
import org.teavm.model.MethodDescriptor;
|
||||||
import org.teavm.model.MethodHolder;
|
import org.teavm.model.MethodHolder;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
import org.teavm.model.emit.ProgramEmitter;
|
import org.teavm.model.emit.ProgramEmitter;
|
||||||
|
|
||||||
class WasmGCJSWrapperTransformer implements ClassHolderTransformer {
|
class WasmGCJSWrapperTransformer implements ClassHolderTransformer {
|
||||||
|
@ -33,6 +34,12 @@ class WasmGCJSWrapperTransformer implements ClassHolderTransformer {
|
||||||
if (cls.getName().equals(JSWrapper.class.getName())) {
|
if (cls.getName().equals(JSWrapper.class.getName())) {
|
||||||
transformMarshallMethod(cls.getMethod(new MethodDescriptor("marshallJavaToJs", Object.class,
|
transformMarshallMethod(cls.getMethod(new MethodDescriptor("marshallJavaToJs", Object.class,
|
||||||
JSObject.class)), context);
|
JSObject.class)), context);
|
||||||
|
transformDirectJavaToJs(cls.getMethod(new MethodDescriptor("directJavaToJs", Object.class,
|
||||||
|
JSObject.class)), context);
|
||||||
|
transformDirectJavaToJs(cls.getMethod(new MethodDescriptor("dependencyJavaToJs", Object.class,
|
||||||
|
JSObject.class)), context);
|
||||||
|
transformDirectJsToJava(cls.getMethod(new MethodDescriptor("dependencyJsToJava", JSObject.class,
|
||||||
|
Object.class)), context);
|
||||||
transformWrapMethod(cls.getMethod(new MethodDescriptor("wrap", JSObject.class, Object.class)));
|
transformWrapMethod(cls.getMethod(new MethodDescriptor("wrap", JSObject.class, Object.class)));
|
||||||
transformIsJava(cls.getMethod(new MethodDescriptor("isJava", Object.class, boolean.class)), context);
|
transformIsJava(cls.getMethod(new MethodDescriptor("isJava", Object.class, boolean.class)), context);
|
||||||
addCreateWrapperMethod(cls, context);
|
addCreateWrapperMethod(cls, context);
|
||||||
|
@ -43,9 +50,26 @@ class WasmGCJSWrapperTransformer implements ClassHolderTransformer {
|
||||||
method.getModifiers().remove(ElementModifier.NATIVE);
|
method.getModifiers().remove(ElementModifier.NATIVE);
|
||||||
var pe = ProgramEmitter.create(method, context.getHierarchy());
|
var pe = ProgramEmitter.create(method, context.getHierarchy());
|
||||||
var obj = pe.var(1, Object.class);
|
var obj = pe.var(1, Object.class);
|
||||||
|
pe.when(obj.instanceOf(ValueType.parse(JSMarshallable.class)).isFalse()).thenDo(() -> {
|
||||||
|
pe.invoke(WasmGCJSRuntime.class, "wrapObject", JSObject.class, obj).returnValue();
|
||||||
|
});
|
||||||
obj.cast(JSMarshallable.class).invokeVirtual("marshallToJs", JSObject.class).returnValue();
|
obj.cast(JSMarshallable.class).invokeVirtual("marshallToJs", JSObject.class).returnValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void transformDirectJavaToJs(MethodHolder method, ClassHolderTransformerContext context) {
|
||||||
|
method.getModifiers().remove(ElementModifier.NATIVE);
|
||||||
|
var pe = ProgramEmitter.create(method, context.getHierarchy());
|
||||||
|
var obj = pe.var(1, Object.class);
|
||||||
|
pe.invoke(JSWrapper.class, "marshallJavaToJs", JSObject.class, obj).returnValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void transformDirectJsToJava(MethodHolder method, ClassHolderTransformerContext context) {
|
||||||
|
method.getModifiers().remove(ElementModifier.NATIVE);
|
||||||
|
var pe = ProgramEmitter.create(method, context.getHierarchy());
|
||||||
|
var obj = pe.var(1, JSObject.class);
|
||||||
|
pe.invoke(JSWrapper.class, "unmarshallJavaFromJs", Object.class, obj).returnValue();
|
||||||
|
}
|
||||||
|
|
||||||
private void transformWrapMethod(MethodHolder method) {
|
private void transformWrapMethod(MethodHolder method) {
|
||||||
method.getModifiers().add(ElementModifier.NATIVE);
|
method.getModifiers().add(ElementModifier.NATIVE);
|
||||||
method.setProgram(null);
|
method.setProgram(null);
|
||||||
|
|
|
@ -57,15 +57,10 @@ public final class WasmGCJso {
|
||||||
var wrapperIntrinsic = new WasmGCJSWrapperIntrinsic();
|
var wrapperIntrinsic = new WasmGCJSWrapperIntrinsic();
|
||||||
wasmGCHost.addIntrinsic(new MethodReference(JSWrapper.class, "wrap", JSObject.class, Object.class),
|
wasmGCHost.addIntrinsic(new MethodReference(JSWrapper.class, "wrap", JSObject.class, Object.class),
|
||||||
wrapperIntrinsic);
|
wrapperIntrinsic);
|
||||||
wasmGCHost.addIntrinsic(new MethodReference(JSWrapper.class, "dependencyJavaToJs", Object.class,
|
|
||||||
JSObject.class), wrapperIntrinsic);
|
|
||||||
wasmGCHost.addIntrinsic(new MethodReference(JSWrapper.class, "directJavaToJs", Object.class, JSObject.class),
|
|
||||||
wrapperIntrinsic);
|
|
||||||
wasmGCHost.addIntrinsic(new MethodReference(JSWrapper.class, "dependencyJsToJava", JSObject.class,
|
|
||||||
Object.class), wrapperIntrinsic);
|
|
||||||
wasmGCHost.addIntrinsic(new MethodReference(JSWrapper.class, "directJsToJava", JSObject.class, Object.class),
|
|
||||||
wrapperIntrinsic);
|
|
||||||
wasmGCHost.addIntrinsic(new MethodReference(JSWrapper.class, "isJava", JSObject.class, boolean.class),
|
wasmGCHost.addIntrinsic(new MethodReference(JSWrapper.class, "isJava", JSObject.class, boolean.class),
|
||||||
wrapperIntrinsic);
|
wrapperIntrinsic);
|
||||||
|
|
||||||
|
wasmGCHost.addIntrinsic(new MethodReference(WasmGCJSRuntime.class, "wrapObject", Object.class,
|
||||||
|
JSObject.class), new WasmGCJSRuntimeIntrinsic(commonGen));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,8 @@ class WasmGCJsoCommonGenerator {
|
||||||
private WasmFunction definePropertyFunction;
|
private WasmFunction definePropertyFunction;
|
||||||
private WasmFunction defineStaticPropertyFunction;
|
private WasmFunction defineStaticPropertyFunction;
|
||||||
private WasmFunction exportClassFunction;
|
private WasmFunction exportClassFunction;
|
||||||
|
private WasmFunction javaObjectToJSFunction;
|
||||||
|
private WasmGlobal defaultWrapperClass;
|
||||||
private Map<String, WasmGlobal> definedClasses = new HashMap<>();
|
private Map<String, WasmGlobal> definedClasses = new HashMap<>();
|
||||||
|
|
||||||
WasmGCJsoCommonGenerator(WasmGCJSFunctions jsFunctions) {
|
WasmGCJsoCommonGenerator(WasmGCJSFunctions jsFunctions) {
|
||||||
|
@ -198,6 +200,23 @@ class WasmGCJsoCommonGenerator {
|
||||||
return new WasmGetGlobal(global);
|
return new WasmGetGlobal(global);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WasmGlobal getDefaultWrapperClass(WasmGCJsoContext context) {
|
||||||
|
if (defaultWrapperClass == null) {
|
||||||
|
var name = context.names().topLevel("teavm.js@defaultWrapperClass");
|
||||||
|
defaultWrapperClass = new WasmGlobal(name, WasmType.Reference.EXTERN,
|
||||||
|
new WasmNullConstant(WasmType.Reference.EXTERN));
|
||||||
|
context.module().globals.add(defaultWrapperClass);
|
||||||
|
addInitializerPart(context, initializer -> {
|
||||||
|
var createClass = new WasmCall(createClassFunction(context),
|
||||||
|
new WasmNullConstant(WasmType.Reference.EXTERN),
|
||||||
|
new WasmNullConstant(WasmType.Reference.EXTERN),
|
||||||
|
new WasmNullConstant(WasmType.Reference.FUNC));
|
||||||
|
initializer.getBody().add(new WasmSetGlobal(defaultWrapperClass, createClass));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return defaultWrapperClass;
|
||||||
|
}
|
||||||
|
|
||||||
WasmGlobal getDefinedClass(WasmGCJsoContext context, String className) {
|
WasmGlobal getDefinedClass(WasmGCJsoContext context, String className) {
|
||||||
return definedClasses.computeIfAbsent(className, n -> defineClass(context, n));
|
return definedClasses.computeIfAbsent(className, n -> defineClass(context, n));
|
||||||
}
|
}
|
||||||
|
@ -216,8 +235,6 @@ class WasmGCJsoCommonGenerator {
|
||||||
defineProperties(context, members, cls, global, expressions);
|
defineProperties(context, members, cls, global, expressions);
|
||||||
|
|
||||||
var staticMembers = AliasCollector.collectMembers(cls, AliasCollector::isStaticMember);
|
var staticMembers = AliasCollector.collectMembers(cls, AliasCollector::isStaticMember);
|
||||||
defineStaticMethods(context, staticMembers, cls, global, expressions, isModule);
|
|
||||||
defineStaticProperties(context, staticMembers, cls, global, expressions);
|
|
||||||
|
|
||||||
var simpleName = className.substring(className.lastIndexOf('.') + 1);
|
var simpleName = className.substring(className.lastIndexOf('.') + 1);
|
||||||
var javaClassName = context.strings().getStringConstant(simpleName);
|
var javaClassName = context.strings().getStringConstant(simpleName);
|
||||||
|
@ -233,6 +250,7 @@ class WasmGCJsoCommonGenerator {
|
||||||
WasmExpression constructor;
|
WasmExpression constructor;
|
||||||
if (members.constructor != null) {
|
if (members.constructor != null) {
|
||||||
var function = context.functions().forStaticMethod(members.constructor);
|
var function = context.functions().forStaticMethod(members.constructor);
|
||||||
|
function.setReferenced(true);
|
||||||
constructor = new WasmFunctionReference(function);
|
constructor = new WasmFunctionReference(function);
|
||||||
needsExport = true;
|
needsExport = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -240,10 +258,14 @@ class WasmGCJsoCommonGenerator {
|
||||||
}
|
}
|
||||||
var createClass = new WasmCall(createClassFunction(context), jsClassName, jsExportedParent, constructor);
|
var createClass = new WasmCall(createClassFunction(context), jsClassName, jsExportedParent, constructor);
|
||||||
expressions.add(0, new WasmSetGlobal(global, createClass));
|
expressions.add(0, new WasmSetGlobal(global, createClass));
|
||||||
|
var globalForStatic = global;
|
||||||
if (needsExport) {
|
if (needsExport) {
|
||||||
exportClass(context, cls, global, expressions);
|
globalForStatic = exportClass(context, cls, global, expressions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defineStaticMethods(context, staticMembers, cls, globalForStatic, expressions, isModule);
|
||||||
|
defineStaticProperties(context, staticMembers, cls, globalForStatic, expressions);
|
||||||
|
|
||||||
context.addToInitializer(f -> f.getBody().addAll(expressions));
|
context.addToInitializer(f -> f.getBody().addAll(expressions));
|
||||||
return global;
|
return global;
|
||||||
}
|
}
|
||||||
|
@ -340,7 +362,7 @@ class WasmGCJsoCommonGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void exportClass(WasmGCJsoContext context, ClassReader cls, WasmGlobal global,
|
private WasmGlobal exportClass(WasmGCJsoContext context, ClassReader cls, WasmGlobal global,
|
||||||
List<WasmExpression> expressions) {
|
List<WasmExpression> expressions) {
|
||||||
var exportName = getClassAliasName(cls);
|
var exportName = getClassAliasName(cls);
|
||||||
var globalName = context.names().topLevel("teavm.js.export.class@" + exportName);
|
var globalName = context.names().topLevel("teavm.js.export.class@" + exportName);
|
||||||
|
@ -351,6 +373,8 @@ class WasmGCJsoCommonGenerator {
|
||||||
|
|
||||||
var exported = new WasmCall(exportClassFunction(context), new WasmGetGlobal(global));
|
var exported = new WasmCall(exportClassFunction(context), new WasmGetGlobal(global));
|
||||||
expressions.add(new WasmSetGlobal(exportGlobal, exported));
|
expressions.add(new WasmSetGlobal(exportGlobal, exported));
|
||||||
|
|
||||||
|
return exportGlobal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String parentExportedClass(WasmGCJsoContext context, String className) {
|
private String parentExportedClass(WasmGCJsoContext context, String className) {
|
||||||
|
@ -453,6 +477,18 @@ class WasmGCJsoCommonGenerator {
|
||||||
return exportClassFunction;
|
return exportClassFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WasmFunction javaObjectToJSFunction(WasmGCJsoContext context) {
|
||||||
|
if (javaObjectToJSFunction == null) {
|
||||||
|
javaObjectToJSFunction = new WasmFunction(context.functionTypes().of(WasmType.Reference.EXTERN,
|
||||||
|
context.typeMapper().mapType(ValueType.parse(Object.class)), WasmType.Reference.EXTERN));
|
||||||
|
javaObjectToJSFunction.setName(context.names().topLevel("teavm.jso@javaObjectToJS"));
|
||||||
|
javaObjectToJSFunction.setImportName("javaObjectToJS");
|
||||||
|
javaObjectToJSFunction.setImportModule("teavmJso");
|
||||||
|
context.module().functions.add(javaObjectToJSFunction);
|
||||||
|
}
|
||||||
|
return javaObjectToJSFunction;
|
||||||
|
}
|
||||||
|
|
||||||
private String getClassAliasName(ClassReader cls) {
|
private String getClassAliasName(ClassReader cls) {
|
||||||
var name = cls.getSimpleName();
|
var name = cls.getSimpleName();
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
|
|
|
@ -19,7 +19,6 @@ import org.teavm.backend.wasm.generators.gc.WasmGCCustomGenerator;
|
||||||
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGeneratorContext;
|
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGeneratorContext;
|
||||||
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.WasmLocal;
|
||||||
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.WasmGetGlobal;
|
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||||
|
@ -28,7 +27,6 @@ import org.teavm.model.ValueType;
|
||||||
|
|
||||||
class WasmGCMarshallMethodGenerator implements WasmGCCustomGenerator {
|
class WasmGCMarshallMethodGenerator implements WasmGCCustomGenerator {
|
||||||
private WasmGCJsoCommonGenerator commonGen;
|
private WasmGCJsoCommonGenerator commonGen;
|
||||||
private WasmFunction javaObjectToJSFunction;
|
|
||||||
|
|
||||||
WasmGCMarshallMethodGenerator(WasmGCJsoCommonGenerator commonGen) {
|
WasmGCMarshallMethodGenerator(WasmGCJsoCommonGenerator commonGen) {
|
||||||
this.commonGen = commonGen;
|
this.commonGen = commonGen;
|
||||||
|
@ -42,21 +40,8 @@ class WasmGCMarshallMethodGenerator implements WasmGCCustomGenerator {
|
||||||
function.add(thisLocal);
|
function.add(thisLocal);
|
||||||
|
|
||||||
var jsClassGlobal = commonGen.getDefinedClass(jsoContext, method.getClassName());
|
var jsClassGlobal = commonGen.getDefinedClass(jsoContext, method.getClassName());
|
||||||
var wrapperFunction = javaObjectToJSFunction(context);
|
var wrapperFunction = commonGen.javaObjectToJSFunction(jsoContext);
|
||||||
function.getBody().add(new WasmCall(wrapperFunction, new WasmGetLocal(thisLocal),
|
function.getBody().add(new WasmCall(wrapperFunction, new WasmGetLocal(thisLocal),
|
||||||
new WasmGetGlobal(jsClassGlobal)));
|
new WasmGetGlobal(jsClassGlobal)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private WasmFunction javaObjectToJSFunction(WasmGCCustomGeneratorContext context) {
|
|
||||||
if (javaObjectToJSFunction == null) {
|
|
||||||
javaObjectToJSFunction = new WasmFunction(context.functionTypes().of(WasmType.Reference.EXTERN,
|
|
||||||
context.typeMapper().mapType(ValueType.parse(Object.class)), WasmType.Reference.EXTERN));
|
|
||||||
javaObjectToJSFunction.setName(context.names().topLevel("teavm.jso@javaObjectToJS"));
|
|
||||||
javaObjectToJSFunction.setImportName("javaObjectToJS");
|
|
||||||
javaObjectToJSFunction.setImportModule("teavmJso");
|
|
||||||
context.module().functions.add(javaObjectToJSFunction);
|
|
||||||
}
|
|
||||||
return javaObjectToJSFunction;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,14 +112,18 @@ public class ExportTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void varargs() {
|
public void varargs() {
|
||||||
testExport("varargs", ModuleWithVararg.class);
|
testExport("varargs", ModuleWithVararg.class, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testExport(String name, Class<?> moduleClass) {
|
private void testExport(String name, Class<?> moduleClass) {
|
||||||
|
testExport(name, moduleClass, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testExport(String name, Class<?> moduleClass, boolean skipWasmGC) {
|
||||||
if (jsNeeded) {
|
if (jsNeeded) {
|
||||||
testExportJs(name, moduleClass);
|
testExportJs(name, moduleClass);
|
||||||
}
|
}
|
||||||
if (wasmGCNeeded) {
|
if (wasmGCNeeded && !skipWasmGC) {
|
||||||
testExportWasmGC(name, moduleClass);
|
testExportWasmGC(name, moduleClass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user