wasm gc: add support for importing modules in more cases

This commit is contained in:
Alexey Andreev 2024-10-17 20:18:56 +02:00
parent e4a2550cc6
commit f3e035148d
11 changed files with 116 additions and 16 deletions

View File

@ -89,7 +89,7 @@ public class DisassemblyImportSectionListener extends BaseDisassemblyListener im
}
@Override
public void global(WasmHollowType type) {
public void global(WasmHollowType type, boolean mutable) {
writer.address().write("(import \"").write(currentModule).write("\" \"")
.write(currentName).write("\" ");
writer.write("(global ");
@ -99,9 +99,15 @@ public class DisassemblyImportSectionListener extends BaseDisassemblyListener im
writer.write(" $").write(name);
}
writer.endLinkTarget();
writer.write(" (type ");
writer.write(" ");
if (mutable) {
writer.write("(mut ");
}
writeType(type);
writer.write("))").eol();
if (mutable) {
writer.write(")");
}
writer.write(")").eol();
++globalIndex;
}
}

View File

@ -37,6 +37,7 @@ import org.teavm.backend.wasm.model.WasmFunction;
import org.teavm.backend.wasm.model.WasmModule;
import org.teavm.backend.wasm.model.WasmTag;
import org.teavm.backend.wasm.runtime.gc.WasmGCSupport;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.ClassHierarchy;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier;
@ -67,6 +68,7 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
private boolean strict;
private String entryPoint;
private Consumer<WasmGCInitializerContributor> initializerContributors;
private Diagnostics diagnostics;
public WasmGCGenerationContext(WasmModule module, WasmGCVirtualTableProvider virtualTables,
WasmGCTypeMapper typeMapper, WasmFunctionTypes functionTypes, ListableClassReaderSource classes,
@ -75,7 +77,8 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
WasmGCStandardClasses standardClasses, WasmGCStringProvider strings,
WasmGCCustomGeneratorProvider customGenerators, WasmGCIntrinsicProvider intrinsics,
WasmGCNameProvider names, boolean strict, String entryPoint,
Consumer<WasmGCInitializerContributor> initializerContributors) {
Consumer<WasmGCInitializerContributor> initializerContributors,
Diagnostics diagnostics) {
this.module = module;
this.virtualTables = virtualTables;
this.typeMapper = typeMapper;
@ -94,6 +97,7 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
this.strict = strict;
this.entryPoint = entryPoint;
this.initializerContributors = initializerContributors;
this.diagnostics = diagnostics;
}
public WasmGCClassInfoProvider classInfoProvider() {
@ -202,6 +206,10 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
return intrinsics;
}
public Diagnostics diagnostics() {
return diagnostics;
}
public Collection<String> getInterfaceImplementors(String className) {
if (interfaceImplementors == null) {
fillInterfaceImplementors();

View File

@ -84,6 +84,7 @@ import org.teavm.backend.wasm.model.expression.WasmTest;
import org.teavm.backend.wasm.model.expression.WasmThrow;
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
import org.teavm.backend.wasm.runtime.StringInternPool;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.ClassHierarchy;
import org.teavm.model.ElementModifier;
import org.teavm.model.FieldReference;
@ -849,6 +850,16 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
return context.entryPoint();
}
@Override
public Diagnostics diagnostics() {
return context.diagnostics();
}
@Override
public MethodReference currentMethod() {
return currentMethod;
}
@Override
public void addToInitializer(Consumer<WasmFunction> initializerContributor) {
context.addToInitializer(initializerContributor);

View File

@ -366,7 +366,8 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
names,
strict,
entryPoint,
initializerContributors
initializerContributors,
diagnostics
);
}
return context;

View File

@ -30,7 +30,9 @@ import org.teavm.backend.wasm.model.WasmFunction;
import org.teavm.backend.wasm.model.WasmModule;
import org.teavm.backend.wasm.model.WasmTag;
import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.ClassHierarchy;
import org.teavm.model.MethodReference;
public interface WasmGCIntrinsicContext {
WasmExpression generate(Expr expr);
@ -63,5 +65,9 @@ public interface WasmGCIntrinsicContext {
String entryPoint();
Diagnostics diagnostics();
MethodReference currentMethod();
void addToInitializer(Consumer<WasmFunction> initializerContributor);
}

View File

@ -22,7 +22,7 @@ public interface ImportSectionListener {
default void function(int typeIndex) {
}
default void global(WasmHollowType type) {
default void global(WasmHollowType type, boolean mutable) {
}
default void endEntry() {

View File

@ -45,7 +45,7 @@ public class ImportSectionParser extends BaseSectionParser {
}
case 3: {
var valueType = reader.readType();
listener.global(valueType);
listener.global(valueType, reader.readLEB() != 0);
break;
}
default:

View File

@ -619,7 +619,7 @@ async function wrapImports(wasmModule, imports) {
if (names === void 0) {
let namesByModule = [];
names = namesByModule;
propertiesToAdd[name] = names;
propertiesToAdd[module] = names;
promises.push((async () => {
let moduleInstance = await import(module);
let importsByModule = {};

View File

@ -29,11 +29,14 @@ import org.teavm.backend.wasm.model.expression.WasmBlock;
import org.teavm.backend.wasm.model.expression.WasmBranch;
import org.teavm.backend.wasm.model.expression.WasmCall;
import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
import org.teavm.backend.wasm.model.expression.WasmIsNull;
import org.teavm.backend.wasm.model.expression.WasmThrow;
import org.teavm.backend.wasm.runtime.gc.WasmGCSupport;
import org.teavm.jso.JSObject;
import org.teavm.jso.impl.JS;
import org.teavm.jso.impl.JSMethods;
import org.teavm.model.CallLocation;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
@ -49,7 +52,6 @@ class WasmGCJSIntrinsic implements WasmGCIntrinsic {
@Override
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) {
var jsoContext = WasmGCJsoContext.wrap(context);
switch (invocation.getMethod().getName()) {
case "wrap":
return wrapString(invocation.getArguments().get(0), context);
@ -69,13 +71,79 @@ class WasmGCJSIntrinsic implements WasmGCIntrinsic {
return arrayItem(invocation, context);
case "get":
case "getPure":
return new WasmCall(functions.getGet(jsoContext), context.generate(invocation.getArguments().get(0)),
context.generate(invocation.getArguments().get(1)));
return getProperty(invocation, context);
case "importModule":
return importModule(invocation, context);
default:
throw new IllegalArgumentException();
}
}
private WasmExpression getProperty(InvocationExpr invocation, WasmGCIntrinsicContext context) {
var result = tryGetFromModule(invocation, context);
if (result != null) {
return result;
}
var jsoContext = WasmGCJsoContext.wrap(context);
return new WasmCall(functions.getGet(jsoContext), context.generate(invocation.getArguments().get(0)),
context.generate(invocation.getArguments().get(1)));
}
private WasmExpression tryGetFromModule(InvocationExpr invocation, WasmGCIntrinsicContext context) {
var target = invocation.getArguments().get(0);
if (!(target instanceof InvocationExpr)) {
return null;
}
var targetCall = (InvocationExpr) target;
if (!targetCall.getMethod().equals(JSMethods.IMPORT_MODULE)) {
return null;
}
var moduleName = extractString(targetCall.getArguments().get(0));
if (moduleName == null) {
return null;
}
var property = invocation.getArguments().get(1);
if (!(property instanceof InvocationExpr)) {
return null;
}
var propertyCall = (InvocationExpr) property;
if (!propertyCall.getMethod().equals(JSMethods.WRAP_STRING)) {
return null;
}
var name = extractString(propertyCall.getArguments().get(0));
if (name == null) {
return null;
}
var jsoContext = WasmGCJsoContext.wrap(context);
var global = commonGen.getImportGlobal(jsoContext, moduleName, name);
return new WasmGetGlobal(global);
}
private WasmExpression importModule(InvocationExpr invocation, WasmGCIntrinsicContext context) {
var jsoContext = WasmGCJsoContext.wrap(context);
var nameArg = invocation.getArguments().get(0);
var name = extractString(nameArg);
if (name == null) {
context.diagnostics().error(new CallLocation(context.currentMethod(), invocation.getLocation()),
"Invalid JS module import call");
}
var global = commonGen.getImportGlobal(jsoContext, name, "__self__");
return new WasmGetGlobal(global);
}
private String extractString(Expr expr) {
if (!(expr instanceof ConstantExpr)) {
return null;
}
var constant = ((ConstantExpr) expr).getValue();
if (!(constant instanceof String)) {
return null;
}
return (String) constant;
}
private WasmExpression wrapString(Expr stringExpr, WasmGCIntrinsicContext context) {
if (stringExpr instanceof ConstantExpr) {
var constantExpr = (ConstantExpr) stringExpr;

View File

@ -57,6 +57,8 @@ public final class WasmGCJso {
jsIntrinsic);
wasmGCHost.addIntrinsic(new MethodReference(JS.class, "getPure", JSObject.class, JSObject.class,
JSObject.class), jsIntrinsic);
wasmGCHost.addIntrinsic(new MethodReference(JS.class, "importModule", String.class, JSObject.class),
jsIntrinsic);
var wrapperIntrinsic = new WasmGCJSWrapperIntrinsic();
wasmGCHost.addIntrinsic(new MethodReference(JSWrapper.class, "wrap", JSObject.class, Object.class),

View File

@ -26,6 +26,7 @@ import org.teavm.junit.JsModuleTest;
import org.teavm.junit.OnlyPlatform;
import org.teavm.junit.ServeJS;
import org.teavm.junit.SkipJVM;
import org.teavm.junit.SkipPlatform;
import org.teavm.junit.TeaVMTestRunner;
import org.teavm.junit.TestPlatform;
@ -39,14 +40,14 @@ public class ImportModuleTest {
"org/teavm/jso/test/amd.js",
"org/teavm/jso/test/amdModule.js"
})
@OnlyPlatform(TestPlatform.JAVASCRIPT)
@SkipPlatform(TestPlatform.WEBASSEMBLY_GC)
public void amd() {
assertEquals(23, runTestFunction());
}
@Test
@AttachJavaScript("org/teavm/jso/test/commonjs.js")
@OnlyPlatform(TestPlatform.JAVASCRIPT)
@SkipPlatform(TestPlatform.WEBASSEMBLY_GC)
public void commonjs() {
assertEquals(23, runTestFunction());
}
@ -54,7 +55,6 @@ public class ImportModuleTest {
@Test
@JsModuleTest
@ServeJS(from = "org/teavm/jso/test/es2015.js", as = "testModule.js")
@OnlyPlatform({TestPlatform.JAVASCRIPT, TestPlatform.WEBASSEMBLY_GC})
public void es2015() {
assertEquals(23, runTestFunction());
}
@ -62,7 +62,6 @@ public class ImportModuleTest {
@Test
@JsModuleTest
@ServeJS(from = "org/teavm/jso/test/classWithConstructorInModule.js", as = "testModule.js")
@OnlyPlatform(TestPlatform.JAVASCRIPT)
public void classConstructor() {
var o = new ClassWithConstructorInModule();
assertEquals(99, o.getFoo());
@ -75,7 +74,6 @@ public class ImportModuleTest {
@Test
@JsModuleTest
@ServeJS(from = "org/teavm/jso/test/classWithConstructorInModule.js", as = "testModule.js")
@OnlyPlatform(TestPlatform.JAVASCRIPT)
public void topLevel() {
assertEquals("top level", ClassWithConstructorInModule.topLevelFunction());
assertEquals("top level prop", ClassWithConstructorInModule.getTopLevelProperty());