From a2167ed043374e2d822c66e51ce7ad95a2ac1328 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 17 Dec 2024 19:07:18 +0100 Subject: [PATCH 1/3] Parse wasm modules with JS API limits by default. Memory count limit should always be 1 if wasm.MultiMemory=false. Result count limit should always be 1 if wasm.MultiValue=false. (cherry picked from commit b8f8e78665b2dd81ef450bea28e7ceb5a1183e80) --- .../org/graalvm/wasm/test/WasmJsApiSuite.java | 8 ++--- .../WasmImplementationLimitationsSuite.java | 4 +-- .../suites/validation/ValidationSuite.java | 19 ++++++----- .../src/org/graalvm/wasm/ModuleLimits.java | 34 ++++++++----------- .../src/org/graalvm/wasm/WasmLanguage.java | 9 ++--- .../src/org/graalvm/wasm/api/JsConstants.java | 6 +--- .../src/org/graalvm/wasm/api/WebAssembly.java | 6 ++-- 7 files changed, 37 insertions(+), 49 deletions(-) diff --git a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmJsApiSuite.java b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmJsApiSuite.java index 0b96d73515be..14634f78c219 100644 --- a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmJsApiSuite.java +++ b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmJsApiSuite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -835,13 +835,11 @@ public void testExportCountsLimit() throws IOException { context.readModule(binaryWithMixedExports, limits); final int noLimit = Integer.MAX_VALUE; - limits = new ModuleLimits(noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, 6, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, - noLimit); + limits = new ModuleLimits(noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, 6, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit); context.readModule(binaryWithMixedExports, limits); try { - limits = new ModuleLimits(noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, 5, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, - noLimit); + limits = new ModuleLimits(noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, 5, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit); context.readModule(binaryWithMixedExports, limits); Assert.fail("Should have failed - export count exceeds the limit"); } catch (WasmException ex) { diff --git a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/WasmImplementationLimitationsSuite.java b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/WasmImplementationLimitationsSuite.java index 6928f69af351..bb6ce1f2a577 100644 --- a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/WasmImplementationLimitationsSuite.java +++ b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/WasmImplementationLimitationsSuite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -65,7 +65,7 @@ public class WasmImplementationLimitationsSuite { public static Collection data() { return Arrays.asList( stringCase("Table instance - initial size out of bounds", - "table instance size exceeds limit: 2147483648 should be <= 2147483647", + "table instance size exceeds limit: 2147483648 should be <= 10000000", "(table $table1 2147483648 funcref)", Failure.Type.TRAP), stringCase("Memory instance - initial size out of bounds", "memory instance size exceeds limit: 32768 should be <= 32767", diff --git a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/validation/ValidationSuite.java b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/validation/ValidationSuite.java index 346b542d81f1..89f1b6d2f237 100644 --- a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/validation/ValidationSuite.java +++ b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/validation/ValidationSuite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -134,20 +134,23 @@ public static Collection data() { // checked individually on memories and tables // ### Function Types - // Return arity + // Return arity limit (implementation-defined) + // Always <= 1 if wasm.MultiValue=false, else constrained by JS API limits + // "maximum number of return values for any function or block is 1,000". binaryCase( "Function - cannot return more than one value", - "A function can return at most one result.", + "invalid result arity: 2 should be <= 1", // (func $f (result i32) i32.const 42 i32.const 42) "0061 736d 0100 0000 0105 0160 0002 7f03 0201 000a 0801 0600 412a 412a 0b", Failure.Type.INVALID), // ### Table types - // Limits - // Limitation only applies to GraalWasm (max array length) + // Table size limit (implementation-defined) + // Constrained by JS API limits, "maximum size of a table is 10,000,000" + // and in GraalWasm, max array length (near 2**31-1). stringCase( "Table - initial size out of bounds", - "table instance size exceeds limit: 2147483648 should be <= 2147483647", + "table instance size exceeds limit: 2147483648 should be <= 10000000", "(table $table1 2147483648 funcref)", Failure.Type.TRAP), stringCase( @@ -359,12 +362,12 @@ public static Collection data() { // Validated in: BinaryParser#readMemorySection stringCase( "Module - two memories (2 locals)", - "A memory has already been declared in the module.", + "multiple memories: 2 should be <= 1", "(memory $mem1 1) (memory $mem2 1)", Failure.Type.INVALID), stringCase( "Module - two memories (1 local and 1 import)", - "A memory has already been imported in the module.", + "multiple memories: 2 should be <= 1", "(memory $mem1 (import \"some\" \"memory\") 1) (memory $mem2 1)", Failure.Type.INVALID), // Validated in: SymbolTable#validateSingleMemory diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/ModuleLimits.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/ModuleLimits.java index e18184330084..1c4aab15b47c 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/ModuleLimits.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/ModuleLimits.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -52,11 +52,14 @@ * Limits on various aspects of a module. */ public final class ModuleLimits { + + private static final int SINGLE_MEMORY_COUNT_LIMIT = 1; + private static final int SINGLE_RESULT_COUNT_LIMIT = 1; + private final int moduleSizeLimit; private final int typeCountLimit; private final int functionCountLimit; private final int tableCountLimit; - private final int memoryCountLimit; private final int multiMemoryCountLimit; private final int importCountLimit; private final int exportCountLimit; @@ -65,23 +68,21 @@ public final class ModuleLimits { private final int elementSegmentCountLimit; private final int functionSizeLimit; private final int paramCountLimit; - private final int resultCountLimit; private final int multiValueResultCountLimit; private final int localCountLimit; private final int tableInstanceSizeLimit; private final int memoryInstanceSizeLimit; private final long memory64InstanceSizeLimit; - public ModuleLimits(int moduleSizeLimit, int typeCountLimit, int functionCountLimit, int tableCountLimit, int memoryCountLimit, int multiMemoryCountLimit, int importCountLimit, + public ModuleLimits(int moduleSizeLimit, int typeCountLimit, int functionCountLimit, int tableCountLimit, int memoryCountLimit, int importCountLimit, int exportCountLimit, int globalCountLimit, - int dataSegmentCountLimit, int elementSegmentCountLimit, int functionSizeLimit, int paramCountLimit, int resultCountLimit, int multiValueResultCountLimit, int localCountLimit, + int dataSegmentCountLimit, int elementSegmentCountLimit, int functionSizeLimit, int paramCountLimit, int resultCountLimit, int localCountLimit, int tableInstanceSizeLimit, int memoryInstanceSizeLimit, long memory64InstanceSizeLimit) { this.moduleSizeLimit = minUnsigned(moduleSizeLimit, Integer.MAX_VALUE); this.typeCountLimit = minUnsigned(typeCountLimit, Integer.MAX_VALUE); this.functionCountLimit = minUnsigned(functionCountLimit, Integer.MAX_VALUE); this.tableCountLimit = minUnsigned(tableCountLimit, Integer.MAX_VALUE); - this.memoryCountLimit = minUnsigned(memoryCountLimit, Integer.MAX_VALUE); - this.multiMemoryCountLimit = minUnsigned(multiMemoryCountLimit, Integer.MAX_VALUE); + this.multiMemoryCountLimit = minUnsigned(memoryCountLimit, Integer.MAX_VALUE); this.importCountLimit = minUnsigned(importCountLimit, Integer.MAX_VALUE); this.exportCountLimit = minUnsigned(exportCountLimit, Integer.MAX_VALUE); this.globalCountLimit = minUnsigned(globalCountLimit, Integer.MAX_VALUE); @@ -89,8 +90,7 @@ public ModuleLimits(int moduleSizeLimit, int typeCountLimit, int functionCountLi this.elementSegmentCountLimit = minUnsigned(elementSegmentCountLimit, Integer.MAX_VALUE); this.functionSizeLimit = minUnsigned(functionSizeLimit, Integer.MAX_VALUE); this.paramCountLimit = minUnsigned(paramCountLimit, Integer.MAX_VALUE); - this.resultCountLimit = minUnsigned(resultCountLimit, Integer.MAX_VALUE); - this.multiValueResultCountLimit = minUnsigned(multiValueResultCountLimit, Integer.MAX_VALUE); + this.multiValueResultCountLimit = minUnsigned(resultCountLimit, Integer.MAX_VALUE); this.localCountLimit = minUnsigned(localCountLimit, Integer.MAX_VALUE); this.tableInstanceSizeLimit = minUnsigned(tableInstanceSizeLimit, MAX_TABLE_INSTANCE_SIZE); this.memoryInstanceSizeLimit = minUnsigned(memoryInstanceSizeLimit, MAX_MEMORY_INSTANCE_SIZE); @@ -120,8 +120,6 @@ private static long minUnsigned(long a, long b) { Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, - Integer.MAX_VALUE, - Integer.MAX_VALUE, MAX_TABLE_INSTANCE_SIZE, MAX_MEMORY_INSTANCE_SIZE, MAX_MEMORY_64_INSTANCE_SIZE); @@ -143,11 +141,10 @@ public void checkTableCount(int count) { } public void checkMemoryCount(int count, boolean multiMemory) { - if (multiMemory) { - assertUnsignedIntLessOrEqual(count, multiMemoryCountLimit, Failure.MEMORY_COUNT_LIMIT_EXCEEDED); - } else { - assertUnsignedIntLessOrEqual(count, memoryCountLimit, Failure.MEMORY_COUNT_LIMIT_EXCEEDED); + if (!multiMemory) { + assertUnsignedIntLessOrEqual(count, SINGLE_MEMORY_COUNT_LIMIT, Failure.MULTIPLE_MEMORIES); } + assertUnsignedIntLessOrEqual(count, multiMemoryCountLimit, Failure.MEMORY_COUNT_LIMIT_EXCEEDED); } public void checkImportCount(int count) { @@ -179,11 +176,10 @@ public void checkParamCount(int count) { } public void checkResultCount(int count, boolean multiValue) { - if (multiValue) { - assertUnsignedIntLessOrEqual(count, multiValueResultCountLimit, Failure.RESULT_COUNT_LIMIT_EXCEEDED); - } else { - assertUnsignedIntLessOrEqual(count, resultCountLimit, Failure.RESULT_COUNT_LIMIT_EXCEEDED); + if (!multiValue) { + assertUnsignedIntLessOrEqual(count, SINGLE_RESULT_COUNT_LIMIT, Failure.INVALID_RESULT_ARITY); } + assertUnsignedIntLessOrEqual(count, multiValueResultCountLimit, Failure.RESULT_COUNT_LIMIT_EXCEEDED); } public void checkLocalCount(int count) { diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java index 861675d21129..ab17ffb34f20 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -80,8 +80,6 @@ public final class WasmLanguage extends TruffleLanguage { public static final String NAME = "WebAssembly"; public static final String WASM_MIME_TYPE = "application/wasm"; public static final String WASM_SOURCE_NAME_SUFFIX = ".wasm"; - public static final String PARSE_JS_MODULE_MARKER = "js_module_decode"; - public static final String[] PARSE_JS_MODULE_ARGS = {PARSE_JS_MODULE_MARKER}; private static final LanguageReference REFERENCE = LanguageReference.create(WasmLanguage.class); @@ -124,10 +122,7 @@ protected CallTarget parse(ParsingRequest request) { final Source source = request.getSource(); final String moduleName = source.getName(); final byte[] data = source.getBytes().toByteArray(); - ModuleLimits moduleLimits = null; - if (!request.getArgumentNames().isEmpty() && PARSE_JS_MODULE_MARKER.equals(request.getArgumentNames().get(0))) { - moduleLimits = JsConstants.JS_LIMITS; - } + ModuleLimits moduleLimits = JsConstants.JS_LIMITS; final WasmModule module = context.readModule(moduleName, data, moduleLimits); return new ParsedWasmModuleRootNode(this, module, source).getCallTarget(); } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/JsConstants.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/JsConstants.java index b9a421b63bcc..e5b07bd2fca0 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/JsConstants.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/JsConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -56,12 +56,10 @@ private JsConstants() { private static final int GLOBAL_COUNT_LIMIT = 1000000; private static final int DATA_SEGMENT_LIMIT = 100000; private static final int TABLE_COUNT_LIMIT = 100000; - private static final int MEMORY_COUNT_LIMIT = 1; private static final int MULTI_MEMORY_COUNT_LIMIT = 100; private static final int ELEMENT_SEGMENT_LIMIT = 10000000; private static final int FUNCTION_SIZE_LIMIT = 7654321; private static final int PARAM_COUNT_LIMIT = 1000; - private static final int RESULT_COUNT_LIMIT = 1; private static final int MULTI_VALUE_RESULT_COUNT_LIMIT = 1000; private static final int LOCAL_COUNT_LIMIT = 50000; private static final int TABLE_SIZE_LIMIT = 10000000; @@ -72,7 +70,6 @@ private JsConstants() { TYPE_COUNT_LIMIT, FUNCTION_COUNT_LIMIT, TABLE_COUNT_LIMIT, - MEMORY_COUNT_LIMIT, MULTI_MEMORY_COUNT_LIMIT, IMPORT_COUNT_LIMIT, EXPORT_COUNT_LIMIT, @@ -81,7 +78,6 @@ private JsConstants() { ELEMENT_SEGMENT_LIMIT, FUNCTION_SIZE_LIMIT, PARAM_COUNT_LIMIT, - RESULT_COUNT_LIMIT, MULTI_VALUE_RESULT_COUNT_LIMIT, LOCAL_COUNT_LIMIT, TABLE_SIZE_LIMIT, diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java index 8ea8fd84fe20..8b14850a8cc7 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -259,8 +259,8 @@ private static String makeModuleName(byte[] data) { private WasmModuleWithSource moduleDecodeImpl(byte[] data) { String moduleName = makeModuleName(data); - Source source = Source.newBuilder(WasmLanguage.ID, ByteSequence.create(data), moduleName).build(); - CallTarget parseResult = currentContext.environment().parsePublic(source, WasmLanguage.PARSE_JS_MODULE_ARGS); + Source source = Source.newBuilder(WasmLanguage.ID, ByteSequence.create(data), moduleName).mimeType(WasmLanguage.WASM_MIME_TYPE).build(); + CallTarget parseResult = currentContext.environment().parsePublic(source); WasmModule module = WasmLanguage.getParsedModule(parseResult); assert module.limits().equals(JsConstants.JS_LIMITS); return new WasmModuleWithSource(module, source); From cfe34b1ef81ab4e0f967093ef949b57e388707fa Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 17 Dec 2024 19:07:23 +0100 Subject: [PATCH 2/3] Parse wasm modules directly from JS via Env.parsePublic. (cherry picked from commit 5793acc7a5e1a27bb4f7da18c55ab40171059e44) --- .../src/org/graalvm/wasm/WasmLanguage.java | 47 +++++++++++++++---- .../src/org/graalvm/wasm/api/WebAssembly.java | 5 +- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java index ab17ffb34f20..2269caf5ed25 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java @@ -48,12 +48,15 @@ import org.graalvm.options.OptionDescriptors; import org.graalvm.options.OptionValues; import org.graalvm.wasm.api.JsConstants; +import org.graalvm.wasm.api.WasmModuleWithSource; import org.graalvm.wasm.api.WebAssembly; +import org.graalvm.wasm.exception.WasmJsApiException; import org.graalvm.wasm.memory.WasmMemory; import org.graalvm.wasm.predefined.BuiltinModule; import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.ContextThreadLocal; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.TruffleLanguage; @@ -69,17 +72,18 @@ @Registration(id = WasmLanguage.ID, // name = WasmLanguage.NAME, // defaultMimeType = WasmLanguage.WASM_MIME_TYPE, // - byteMimeTypes = WasmLanguage.WASM_MIME_TYPE, // + byteMimeTypes = {WasmLanguage.WASM_MIME_TYPE}, // contextPolicy = TruffleLanguage.ContextPolicy.SHARED, // fileTypeDetectors = WasmFileDetector.class, // interactive = false, // - website = "https://www.graalvm.org/") + website = "https://www.graalvm.org/webassembly/") @ProvidedTags({StandardTags.RootTag.class, StandardTags.RootBodyTag.class, StandardTags.StatementTag.class}) public final class WasmLanguage extends TruffleLanguage { public static final String ID = "wasm"; public static final String NAME = "WebAssembly"; public static final String WASM_MIME_TYPE = "application/wasm"; public static final String WASM_SOURCE_NAME_SUFFIX = ".wasm"; + public static final String MODULE_DECODE = "module_decode"; private static final LanguageReference REFERENCE = LanguageReference.create(WasmLanguage.class); @@ -138,13 +142,40 @@ private ParsedWasmModuleRootNode(WasmLanguage language, WasmModule module, Sourc } @Override - public WasmInstance execute(VirtualFrame frame) { - final WasmContext context = WasmContext.get(this); - WasmInstance instance = context.lookupModuleInstance(module); - if (instance == null) { - instance = context.readInstance(module); + public Object execute(VirtualFrame frame) { + if (frame.getArguments().length == 0) { + final WasmContext context = WasmContext.get(this); + WasmInstance instance = context.lookupModuleInstance(module); + if (instance == null) { + instance = context.readInstance(module); + } + return instance; + } else { + if (frame.getArguments()[0] instanceof String mode) { + if (mode.equals(MODULE_DECODE)) { + return moduleDecode(); + } else { + throw WasmJsApiException.format(WasmJsApiException.Kind.TypeError, "Unsupported first argument: '%s'", mode); + } + } else { + throw WasmJsApiException.format(WasmJsApiException.Kind.TypeError, "First argument must be a string"); + } } - return instance; + } + + @TruffleBoundary + private Object moduleDecode() { + /* + * Get the source used for parsing on the JS side and associate it with the returned + * WasmModule, so that it will be kept alive with the JS WebAssembly.Module object. + */ + Source sourceHandle = getParsingSource(); + return new WasmModuleWithSource(module, sourceHandle); + } + + @TruffleBoundary + private Source getParsingSource() { + return Source.newBuilder(source).build(); } @Override diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java index 8b14850a8cc7..73245ad7586c 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java @@ -334,7 +334,10 @@ private static WasmJsApiException cannotConvertToBytesError(Throwable cause) { private static WasmModule toModule(Object[] args) { checkArgumentCount(args, 1); - if (args[0] instanceof WasmModuleWithSource moduleObject) { + Object arg0 = args[0]; + if (arg0 instanceof WasmModule moduleObject) { + return moduleObject; + } else if (arg0 instanceof WasmModuleWithSource moduleObject) { return moduleObject.module(); } else { throw new WasmJsApiException(WasmJsApiException.Kind.TypeError, "First argument must be wasm module"); From 5c43744287e6b65da16749c32f7d5ab98d4a8400 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 23 Dec 2024 02:19:55 +0100 Subject: [PATCH 3/3] Return WasmModule directly. (cherry picked from commit 40012c6a6c5e5a12ff68c32b45a07af0027ad7ed) --- .../src/org/graalvm/wasm/WasmLanguage.java | 29 +++++++------------ .../src/org/graalvm/wasm/api/WebAssembly.java | 5 ++++ 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java index 2269caf5ed25..0b7e846df38c 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java @@ -48,7 +48,6 @@ import org.graalvm.options.OptionDescriptors; import org.graalvm.options.OptionValues; import org.graalvm.wasm.api.JsConstants; -import org.graalvm.wasm.api.WasmModuleWithSource; import org.graalvm.wasm.api.WebAssembly; import org.graalvm.wasm.exception.WasmJsApiException; import org.graalvm.wasm.memory.WasmMemory; @@ -56,7 +55,6 @@ import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.ContextThreadLocal; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.TruffleLanguage; @@ -141,6 +139,16 @@ private ParsedWasmModuleRootNode(WasmLanguage language, WasmModule module, Sourc this.source = source; } + /** + * The CallTarget returned by {@code parse} supports two calling conventions: + * + *
    + *
  1. (default) zero arguments provided: on the first call, instantiates the decoded module + * and puts it in the context's module instance map; then returns the {@link WasmInstance}. + *
  2. first argument is {@code "module_decode"}: returns the decoded {@link WasmModule} + * (i.e. behaves like {@link WebAssembly#moduleDecode module_decode}). Used by the JS API. + *
+ */ @Override public Object execute(VirtualFrame frame) { if (frame.getArguments().length == 0) { @@ -153,7 +161,7 @@ public Object execute(VirtualFrame frame) { } else { if (frame.getArguments()[0] instanceof String mode) { if (mode.equals(MODULE_DECODE)) { - return moduleDecode(); + return module; } else { throw WasmJsApiException.format(WasmJsApiException.Kind.TypeError, "Unsupported first argument: '%s'", mode); } @@ -163,21 +171,6 @@ public Object execute(VirtualFrame frame) { } } - @TruffleBoundary - private Object moduleDecode() { - /* - * Get the source used for parsing on the JS side and associate it with the returned - * WasmModule, so that it will be kept alive with the JS WebAssembly.Module object. - */ - Source sourceHandle = getParsingSource(); - return new WasmModuleWithSource(module, sourceHandle); - } - - @TruffleBoundary - private Source getParsingSource() { - return Source.newBuilder(source).build(); - } - @Override public SourceSection getSourceSection() { return source.createUnavailableSection(); diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java index 73245ad7586c..2c36798d2216 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java @@ -332,6 +332,11 @@ private static WasmJsApiException cannotConvertToBytesError(Throwable cause) { return (cause == null) ? new WasmJsApiException(kind, message) : new WasmJsApiException(kind, message, cause); } + /** + * Extract a {@link WasmModule} from argument 0. The argument may be a {@link WasmModule} or a + * {@link WasmModuleWithSource} as produced by the CallTarget returned from Env.parse or + * {@link #moduleDecode}, respectively. + */ private static WasmModule toModule(Object[] args) { checkArgumentCount(args, 1); Object arg0 = args[0];